Skip to content

SPU LLVM: Support PUTLLC16 in CellSpurs JobChain management - #17733

Merged
elad335 merged 7 commits into
RPCS3:masterfrom
elad335:send-ppu
Nov 29, 2025
Merged

elad335 merged 7 commits into
RPCS3:masterfrom
elad335:send-ppu

Conversation

@elad335

@elad335 elad335 commented Nov 22, 2025 •

Copy link
Copy Markdown
Contributor

In Hot Shots Golf, one SPU atomic operation stands out more than the rest:
image

This operation, manages acquireship of cellSpurs Jobchain tasks.
After some observation, I've noticed that this atomic operation may be compatible with the PUTLLC16 optimization, which you can learn about here: #15429

But why it wasn't yet compatible for it? for few reasons it turns out.

  1. There is a function call, BRSL, in the middle of the operation. But after inspecting what it does, it does not seem to make sense for the function. But after second inspection, I noticed that register 4 (R4) was used right after the function call. So I figured, that this must be a [[noreturn]] type of function which does not actually return to function. Implementing detection of this eliminates optimization failure number 1 for SPU Mega block size.
image
  1. There are two addresses LQR and STQR refer to, (0x4a20 and 0x4a90), but PUTLLC16 can only refer to one. (which belongs to the atomic operation)
    After inspection, the second address cannot be interleaved with the cache line data of the operation. But, because of the usage of relative loads and stores, a runtime check was added in LLVM code to verify it. (otherwise resorting to the full and heavy PUTLLC)
  2. There is a fast path that skips PUTLLC conditionally, it just so happens to contain a relative store that messes with the detection of PUTLLC16. Making failed paths signal failure only at the reach of the pattern destination fixes this issue. That was s design flaw of PUTLLC16 detection.

Fixes #14724

Note: This pull requests affect both SPU Safe and SPU Mega block sizes.

Before

image

After

image

@elad335 elad335 added CPU Optimization Optimizes existing code LLVM Related to LLVM instruction decoders labels Nov 22, 2025
@woj1993

woj1993 commented Nov 22, 2025

Copy link
Copy Markdown

Hi do you need any types of tests? Also can you marge master to it as there are also new optimizations so it will be hard to compare speed without them here?

@elad335

elad335 commented Nov 22, 2025 •

Copy link
Copy Markdown
Contributor Author

Yes you can test performamce differences.

@RPCS3 RPCS3 deleted a comment from digant73 Nov 22, 2025
@woj1993

woj1993 commented Nov 22, 2025 •

Copy link
Copy Markdown

God of war 3 difference is too small so probably difference in gameplay. In Uncharted 1 I saw difference between 76.5 max (master) and 68..5 on branch but it can be because of gameplay or something. All other stats are similar:
God of war 3
Master:
Zrzut ekranu (609)
Branch:
Zrzut ekranu (611)
Uncharrted 1
Master:
Zrzut ekranu (610)
Branch:
Zrzut ekranu (612)

@kd-11

kd-11 commented Nov 22, 2025

Copy link
Copy Markdown
Contributor

The branch crashes resistance 3. The crash can be reproduced in the "Haven" demo as well.

@elad335
elad335 force-pushed the send-ppu branch 2 times, most recently from 195749d to 5e3d9f7 Compare November 28, 2025 14:02
@elad335

elad335 commented Nov 28, 2025

Copy link
Copy Markdown
Contributor Author

The branch crashes resistance 3. The crash can be reproduced in the "Haven" demo as well.

Resistance 3 is fixed!

@digant73

Copy link
Copy Markdown
Contributor

I made some testing and apparently I didn't get crashes or regressions. On my games, I didn't see performance improvement but probably they are not affected by this changes

_aligned_realloc may return the same pointer if the internal implementation finds it suitable. Fixes Windows' builds.
@elad335
elad335 merged commit d625c1d into RPCS3:master Nov 29, 2025
7 of 9 checks passed
@5kft

5kft commented Nov 29, 2025

Copy link
Copy Markdown
Contributor

This change (RPCS3 build 18413) crashes Ratchet & Clank - Into the Nexus, planet Igliak, immediately when you swingshot across the opening swingshot targets ("SIG: Thread terminated due to fatal error: PPU Trap! Sometimes tweaking the setting "Stub PPU Traps" can be a workaround to this crash."):

rcitncrash

Here is the relevant RPCS3 log excerpt:

·W 0:01:18.044961 {PPU[0x1000012] Thread (fios mediathread) [libfs: 0x01461210]} sys_fs: sys_fs_close(fd=15): Regular file, '/dev_hdd0/game/BCUS99245/USRDIR/built/sound/bank/85/857a2ecc/streaming_sound.dat', Mode: 0x0, Flags: 0x0, Pos/Size: 463.785KB/2.78516MB (0x73f24/0x2c9000)
·! 0:01:18.045516 {PPU[0x1000012] Thread (fios mediathread) [libfs: 0x01460ec0]} sys_fs: sys_fs_fcntl(0xc0000006): /dev_hdd0
·W 0:01:18.045982 {PPU[0x1000012] Thread (fios mediathread) [libfs: 0x01462090]} sys_fs: sys_fs_open(path=“/dev_hdd0/game/BCUS99245/USRDIR/built/sound/bank/85/857a2ecc/streaming_sound.dat”, flags=00, fd=*0xd00a5680, mode=00, arg=*0x0, size=0x0)
·W 0:01:18.046619 {PPU[0x1000012] Thread (fios mediathread) [libfs: 0x01462090]} sys_fs: sys_fs_open(): fd=13, Regular file, '/dev_hdd0/game/BCUS99245/USRDIR/built/sound/bank/85/857a2ecc/streaming_sound.dat', Mode: 0x0, Flags: 0x0, Pos/Size: 0/2.78516MB (0x0/0x2c9000)
·W 0:01:18.046768 {PPU[0x1000012] Thread (fios mediathread) [libfs: 0x01461380]} sys_fs: sys_fs_fstat(fd=13, sb=*0xd00a5894)
·! 0:01:18.815718 {PPU[0x1000000] Thread (main_thread) [0x006cf128]} SYS: 

PPU[0x1000000] main_thread's thread context:
Type: PPU; State: 00[]
Priority: 1001
Stack: 0xd0001000..0xd0010fff
Joiner: detached



r0 : 0x2
r1 : 0xd0010570 -> 00 00 00 00 d0 01 06 60
r2 : 0xd8ee18   -> " then prt("Error: Invalid Spec E"
r3 : 0x1
r4 : 0xfbef90   -> 00 00 00 00 be be be be
r5 : 0x20
r6 : 0x0
r7 : 0x6c64000000000000
r8 : 0x10
r9 : 0x7f7f7f7f7f7f7f7f
r10: 0xebe37f7f7f7f7f7f
r11: 0x808080808080
r12: 0xd0010600 -> 20 00 00 0a ff ff ff ff
r13: 0x20007060 -> 00 00 00 00 00 00 00 00
r14: 0x0
r15: 0x0
r16: 0x0
r17: 0x0
r18: 0x0
r19: 0x0
r20: 0x0
r21: 0x0
r22: 0xfbdbc0   -> 00 40 1f 6c 1e 7c 1e c0
r23: 0x1400
r24: 0x0
r25: 0xfb4d00   -> 00 40 c8 20 30 c0 31 00
r26: 0xfb4a94   -> 01 00 00 09 0e 01 35 00
r27: 0x0
r28: 0x1
r29: 0x0
r30: 0x5
r31: 0xfb4a80   -> 00 00 00 00 00 00 13 f2
CR: 0x48000044, CR0: [LT=0 GT=1 EQ=0 SO=0]
f0 : 0            [                  ] (f32=0x0)
f1 : 8.33333E-05  [0x3f15d867c0000000] (f32=0x38aec33e)
f2 : 0.00833333   [0x3f81111120000000] (f32=0x3c088889)
f3 : 35.5497      [0x4041c65b80000000] (f32=0x420e32dc)
f4 : 0            [                  ] (f32=0x0)
f5 : 0            [                  ] (f32=0x0)
f6 : 0            [                  ] (f32=0x0)
f7 : 1E+06        [0x412e848000000000] (f32=0x49742400)
f8 : 58.5036      [0x404d407700000000] (f32=0x426a03b8)
f9 : -0.125       [0xbfc0000000000000] (f32=0xbe000000)
f10: 0.666668     [0x3fe5555800000000] (f32=0x3f2aaac0)
f11: 0.399766     [0x3fd995c220000000] (f32=0x3eccae11)
f12: -0.0666667   [0xbfb1111120000000] (f32=0xbd888889)
f13: 0.693147     [0x3fe62e42c0000000] (f32=0x3f317216)
f14: 0            [                  ] (f32=0x0)
f15: 0            [                  ] (f32=0x0)
f16: 0            [                  ] (f32=0x0)
f17: 0            [                  ] (f32=0x0)
f18: 0            [                  ] (f32=0x0)
f19: 0            [                  ] (f32=0x0)
f20: 0            [                  ] (f32=0x0)
f21: 0            [                  ] (f32=0x0)
f22: 0            [                  ] (f32=0x0)
f23: 0            [                  ] (f32=0x0)
f24: 0            [                  ] (f32=0x0)
f25: 0            [                  ] (f32=0x0)
f26: 0            [                  ] (f32=0x0)
f27: 0            [                  ] (f32=0x0)
f28: 0            [                  ] (f32=0x0)
f29: 0            [                  ] (f32=0x0)
f30: 0            [                  ] (f32=0x0)
f31: 0.00833333   [0x3f81111120000000] (f32=0x3c088889)
v0 : 3ef73dc2 be99ebf6 befde91c 3eb01aa8 [x: 0.482893 y: -0.300628 z: -0.495919 w: 0.343953]
v1 : d5bd3f3e 66703f53 00a80000 00a80000 [x: -2.60099e+13 y: 2.83634e+23 z: 1.54284e-38 w: 1.54284e-38]
v2 : 010114a0 00fed900 01011f00 00000000 [x: 2.37084e-38 y: 2.34041e-38 z: 2.37158e-38 w: 0]
v3 : 00000000 [x: 0]
v4 : 40800000 [x: 4]
v5 : 433441cd 420f47e3 c20870a6 3f800000 [x: 180.257 y: 35.8202 z: -34.11 w: 1]
v6 : 44340000 [x: 720]
v7 : 33f6a292 3f7fac82 3d4eafcd 00000000 [x: 1.14848e-07 y: 0.998726 z: 0.0504606 w: 0]
v8 : b46c3a3b [x: -2.20004e-07]
v9 : 3e9b956a [x: 0.303874]
v10: b0c9384e 3f7fac82 3d4eaf93 00000000 [x: -1.46407e-09 y: 0.998726 z: 0.0504604 w: 0]
v11: 3f6175e9 3cc3cca6 bef2350b 00000000 [x: 0.880705 y: 0.0239013 z: -0.473061 w: 0]
v12: 3f800000 [x: 1]
v13: 00000000 00000000 00000000 ffffffff [x: 0 y: 0 z: 0 w: -nan]
v14: 3ef73dc2 be99ebf6 befde91c 3eb01aa8 [x: 0.482893 y: -0.300628 z: -0.495919 w: 0.343953]
v15: 3d4eaf93 bd4eaf93 3d4eaf93 bd4eaf93 [x: 0.0504604 y: -0.0504604 z: 0.0504604 w: -0.0504604]
v16: bf7c430f 3ece9f30 be2cec0b be59b769 [x: -0.985398 y: 0.403558 z: -0.168869 w: -0.212614]
v17: 80000000 [x: -0]
v18: 42dfa152 c47722dd 42ce703d 3f800000 [x: 111.815 y: -988.545 z: 103.219 w: 1]
v19: ffffffff [x: -nan]
v20: 00000000 [x: 0]
v21: 00000000 [x: 0]
v22: 00000000 [x: 0]
v23: 00000000 [x: 0]
v24: 00000000 [x: 0]
v25: 00000000 [x: 0]
v26: 00000000 [x: 0]
v27: 00000000 [x: 0]
v28: 00000000 [x: 0]
v29: 00000000 [x: 0]
v30: 00000000 [x: 0]
v31: 00000000 [x: 0]
CIA: 0x6cf128
LR: 0x6cefcc
CTR: 0xf
VRSAVE: 0xffffffff
XER: [CA=0 | OV=0 | SO=0 | CNT=0]
VSCR: [SAT=2972063728320 | NJ=1]
FPSCR: [FL=0 | FG=1 | FE=0 | FU=0]
Reservation Addr: none
Reservation Data (entire cache line):
[0x00] 00020000 00000000 01000000 00000000
[0x10] 4109f000 00000000 01000000 00000000
[0x20] 44905f00 44e05f00 00000001 00000000
[0x30] 01000000 00000000 00000334 00000000
[0x40] 00d51980 00000002 0000013f 00000140
[0x50] 40a00000 00000002 01000000 00000000
[0x60] 00d52ab8 00000004 01000000 00000000
[0x70] 01000000 00000000 01000000 00000000

Call stack:
=========
0x006cf128 (0x0) called
> from 0x006cfaac (sp=0xd0010660)
> from 0x00740244 (sp=0xd00106f0)
> from 0x0073dc04 (sp=0xd0010760)
> from 0x00734044 (sp=0xd0010810)
> from 0x0033b6b0 (sp=0xd00108b0)
> from 0x0033bd5c (sp=0xd00109a0)
> from 0x006a0d9c (sp=0xd0010a50)
> from 0x006a15ac (sp=0xd0010ad0)
> from 0x005753cc (sp=0xd0010b70)
> from 0x00575454 (sp=0xd0010bf0)
> from 0x0058520c (sp=0xd0010c60)
> from 0x00584fa0 (sp=0xd0010d00)

[006cf0d8]  7c 63 20 14: addc       r3,r3,r4
[006cf0dc]  7c 63 28 10: subfc      r3,r3,r5
[006cf0e0]  7c 61 18 14: addc       r3,r1,r3
[006cf0e4]  78 63 00 20: clrldi     r3,r3,32
[006cf0e8]  98 a3 00 70: stb        r5,0x70(r3)
[006cf0ec]  41 80 ff 5c: blt        cr0,0x6cf048 
[006cf0f0]  33 de 00 01: addic      r30,1(r30)
[006cf0f4]  32 f7 04 00: addic      r23,0x400(r23)
[006cf0f8]  33 5a 00 04: addic      r26,4(r26)
[006cf0fc]  33 39 00 80: addic      r25,0x80(r25)
[006cf100]  28 1e 00 05: cmplwi     cr0,r30,5
[006cf104]  41 80 fe 20: blt        cr0,0x6cef24 
[006cf108]  3c 60 00 00: lis        r3,0
[006cf10c]  60 63 b2 26: ori        r3,0xb226(r3) #0xb226h
[006cf110]  7f 1f 19 ae: stbx       r24,r31,r3
[006cf114]  3c 60 00 00: lis        r3,0
[006cf118]  60 63 b2 25: ori        r3,0xb225(r3) #0xb225h
[006cf11c]  7c 7f 18 ae: lbzx       r3,r31,r3
[006cf120]  2c 03 00 00: cmpwi      cr0,r3,0
[006cf124]  41 82 00 08: beq        cr0,0x6cf12c 
[006cf128]  7f e1 08 08: tw         31,r1,r1
[006cf12c]  e8 01 01 00: ld         r0,0x100(r1)
[006cf130]  7c 08 03 a6: mtlr       r0
[006cf134]  ea c1 00 a0: ld         r22,0xa0(r1)
[006cf138]  ea e1 00 a8: ld         r23,0xa8(r1)
[006cf13c]  eb 01 00 b0: ld         r24,0xb0(r1)
[006cf140]  eb 21 00 b8: ld         r25,0xb8(r1)
[006cf144]  eb 41 00 c0: ld         r26,0xc0(r1)
[006cf148]  eb 61 00 c8: ld         r27,0xc8(r1)
[006cf14c]  eb 81 00 d0: ld         r28,0xd0(r1)

·F 0:01:18.816163 {PPU[0x1000000] Thread (main_thread) [0x006cf128]} SIG: Thread terminated due to fatal error: PPU Trap! Sometimes tweaking the setting "Stub PPU Traps" can be a workaround to this crash.
Best values depend on game code, if unsure try 1.
(in file D:\a\rpcs3\rpcs3\rpcs3\Emu\Cell\PPUThread.cpp:3014[:23], in function 'void ppu_trap(ppu_thread &,unsigned __int64)') (error=0x1e7)
·W 0:01:18.823159 {PPU[0x1000000] Thread (main_thread) [0x006cf128]} SYS: Emulation has been frozen! You can either use debugger tools to inspect current emulation state or terminate it.
·! 0:01:18.824739 {PPU Syscall Usage Thread} PPU: PPU Syscall Usage Stats:
	⁂ sys_timer_usleep [1190297]
	⁂ _sys_lwcond_queue_wait [56379]
	⁂ _sys_lwmutex_lock [46813]
	⁂ _sys_lwmutex_unlock [46763]
	⁂ _sys_lwcond_signal_all [28866]
	⁂ _sys_lwcond_signal [26107]
	⁂ sys_event_queue_receive [11768]
	⁂ sys_mutex_lock [10538]
	⁂ sys_mutex_unlock [10537]
	⁂ sys_fs_fcntl [9953]
	⁂ sys_time_get_current_time [9862]
	⁂ sys_fs_stat [9797]
	⁂ sys_fs_read [8317]
	⁂ sys_ppu_thread_set_priority [7264]
	⁂ sys_ppu_thread_get_priority [3639]
	⁂ sys_net_bnet_select [3633]
	⁂ sys_ppu_thread_yield [3632]
	⁂ sys_fs_write [2728]
	⁂ sys_cond_wait [1675]
	⁂ sys_cond_signal [1665]
	⁂ sys_fs_lseek [1263]
	⁂ _sys_lwmutex_create [758]
	⁂ sys_mutex_create [671]
	⁂ sys_fs_fsync [456]
	⁂ sys_mutex_destroy [438]
	⁂ sys_cond_signal_all [374]
	⁂ _sys_lwmutex_destroy [351]
	⁂ sys_cond_create [338]
	⁂ sys_semaphore_wait [235]
	⁂ sys_semaphore_post [221]
	⁂ sys_time_get_timezone [221]
	⁂ sys_cond_destroy [219]
	⁂ sys_rsx_context_iomap [198]
	⁂ sys_mmapper_allocate_shared_memory [197]
	⁂ sys_mmapper_map_shared_memory [197]
	⁂ sys_fs_open [177]
	⁂ sys_fs_fstat [160]
	⁂ sys_fs_close [145]
	⁂ sys_time_get_timebase_frequency [53]
	⁂ sys_semaphore_create [49]
	⁂ _sys_ppu_thread_create [47]
	⁂ sys_ppu_thread_start [47]
	⁂ sys_tty_write [44]
	⁂ _sys_lwcond_create [40]
	⁂ _sys_prx_start_module [38]
	⁂ sys_rsx_context_attribute [15]
	⁂ _sys_prx_load_module [12]
	⁂ _sys_ppu_thread_exit [10]
	⁂ sys_event_queue_create [8]
	⁂ sys_event_port_create [7]
	⁂ sys_event_port_connect_local [7]
	⁂ sys_process_getpid [6]
	⁂ sys_spu_thread_initialize [6]
	⁂ sys_spu_thread_group_connect_event_all_threads [6]
	⁂ sys_mmapper_free_shared_memory [6]
	⁂ sys_mmapper_unmap_shared_memory [6]
	⁂ sys_rsx_attribute [6]
	⁂ sys_process_get_sdk_version [5]
	⁂ sys_spu_thread_write_snr [5]
	⁂ sys_memory_get_user_memory_size [5]
	⁂ sys_memory_allocate [4]
	⁂ sys_ppu_thread_join [3]
	⁂ sys_semaphore_trywait [3]
	⁂ sys_fs_get_block_size [3]
	⁂ sys_process_is_spu_lock_line_reservation_address [2]
	⁂ sys_spu_thread_group_create [2]
	⁂ sys_spu_thread_group_start [2]
	⁂ sys_spu_thread_group_join [2]
	⁂ sys_spu_thread_group_connect_event [2]
	⁂ sys_memory_container_create [2]
	⁂ sys_memory_container_destroy [2]
	⁂ _sys_prx_register_module [2]
	⁂ _sys_prx_get_module_id_by_name [2]
	⁂ sys_net_infoctl [2]
	⁂ sys_fs_disk_free [2]
	⁂ sys_ss_access_control_engine [2]
	⁂ _sys_process_get_paramsfo [1]
	⁂ sys_spu_initialize [1]
	⁂ sys_mmapper_allocate_address [1]
	⁂ sys_mmapper_free_address [1]
	⁂ syscall_462 [1]
	⁂ _sys_prx_load_module_list [1]
	⁂ sys_rsx_memory_allocate [1]
	⁂ sys_rsx_context_allocate [1]
	⁂ sys_rsx_context_iounmap [1]
	⁂ sys_rsx_device_map [1]
	⁂ sys_net_bnet_bind [1]
	⁂ sys_net_bnet_getsockname [1]
	⁂ sys_net_bnet_setsockopt [1]
	⁂ sys_net_bnet_socket [1]
·E 0:01:18.827351 {PPU[0x1000000] Thread (main_thread) [0x006cf128]} SYS: Stat: '_sys_lwmutex_lock' failed with 0x80010005 : CELL_ESRCH, Invalid ID [x18]
·E 0:01:18.827517 {PPU[0x1000000] Thread (main_thread) [0x006cf128]} SYS: Stat: 'sceNpManagerGetStatus' failed with 0x8002aa01 : SCE_NP_ERROR_NOT_INITIALIZED [x14]
·E 0:01:18.827641 {PPU[0x1000000] Thread (main_thread) [0x006cf128]} SYS: Stat: 'cellPadSetActDirect' failed with 0x80121102 : CELL_PAD_ERROR_INVALID_PARAMETER [x5]
·! 0:01:18.827761 {PPU[0x1000000] main_thread} SIG: Thread time: 64.890625s (220.728628Gc); Faults: 63 [rsx:63, spu:0]; [soft:0 hard:0]; Switches:[vol:0 unvol:0]; Wait:[11.869s, spur:0]
·W 0:01:18.828044 SYS: CPU Thread 'PPU[0x1000000] main_thread' terminated abnormally!

I know that "Into the Nexus" has random freezes, but RPCS3 builds prior to versions including this PR work fine here. This crash is 100% reproducible every time. I also looked everywhere and can't seem to find an option "Stub PPU Traps" in RPCS3 to give that a try...

@Darkhost1999

Copy link
Copy Markdown
Contributor

Because this change is merged into master can you open a regression ticket following all the information that the template requests.
When it asks for a log it means the file not the contents of the file. So just upload the entire rpcs3.log file itself without opening it.

@AniLeo

AniLeo commented Nov 29, 2025

Copy link
Copy Markdown
Member

Any issues stemming from this need to go into a new regression ticket, following the template with log file, otherwise they will be missed

@5kft

5kft commented Nov 29, 2025

Copy link
Copy Markdown
Contributor

Done, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CPU LLVM Related to LLVM instruction decoders Optimization Optimizes existing code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Regression] Performance Regressions in Hot Shots Golf: Out of Bounds (#11904, #12523)

7 participants