<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/60322>60322</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[X86,FMA] SPEC CPU2006/410.bwaves: suboptimal FMA generation
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
vzakhari
</td>
</tr>
</table>
<pre>
The issue was noticed on Icelake CPU where the benchmark runs 1.38x slower when compiled with `-march=native` vs w/o this option.
There is a single loop that runs 1.5x slower, in `mat_times_vec` function from `block_solver.f`:
```
178 do m=1,nb 179 y(l,i,j,k)=y(l,i,j,k)+ 180 1 a(l,m,i,j,k)*x(m,i,j,k)+
181 2 axp(l,m,i,j,k)*x(m,ip1,j,k)+
182 3 ayp(l,m,i,j,k)*x(m,i,jp1,k)+
183 4 azp(l,m,i,j,k)*x(m,i,j,kp1)+
184 5 axm(l,m,i,j,k)*x(m,im1,j,k)+ 185 6 aym(l,m,i,j,k)*x(m,i,jm1,k)+
186 7 azm(l,m,i,j,k)*x(m,i,j,km1)
187 enddo
```
The trip count `nb` is equal to 5.
This is the original LLVM IR produced by `Flang` for this module: [block_solver.orig.ll.gz](https://github.com/llvm/llvm-project/files/10514310/block_solver.orig.ll.gz)
`clang` invocation to reproduce `-march=native` behavior:
```
clang -cc1 -triple x86_64-unknown-linux-gnu -emit-obj -disable-free -clear-ast-before-backend -main-file-name block_solver.ll -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -menable-no-infs -menable-no-nans -fapprox-func -funsafe-math-optimizations -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -funwind-tables=2 -target-cpu icelake-server -target-feature -avx512pf -target-feature -tsxldtrk -target-feature +cx16 -target-feature +sahf -target-feature -tbm -target-feature +avx512ifma -target-feature +sha -target-feature +crc32 -target-feature -fma4 -target-feature +vpclmulqdq -target-feature +prfchw -target-feature +bmi2 -target-feature -cldemote -target-feature +fsgsbase -target-feature -avx512bf16 -target-feature -amx-tile -target-feature -raoint -target-feature -uintr -target-feature +gfni -target-feature +popcnt -target-feature -ptwrite -target-feature +aes -target-feature +avx512bitalg -target-feature -movdiri -target-feature -widekl -target-feature +xsaves -target-feature -avx512er -target-feature -avxvnni -target-feature -avx512fp16 -target-feature +avx512vnni -target-feature -amx-bf16 -target-feature -avxvnniint8 -target-feature +avx512vpopcntdq -target-feature +pconfig -target-feature +clwb -target-feature -cmpccxadd -target-feature +avx512f -target-feature +xsavec -target-feature -clzero -target-feature +pku -target-feature -amx-fp16 -target-feature +mmx -target-feature -lwp -target-feature +rdpid -target-feature -xop -target-feature +rdseed -target-feature -waitpkg -target-feature -prefetchi -target-feature -kl -target-feature -movdir64b -target-feature -sse4a -target-feature +avx512bw -target-feature -avxneconvert -target-feature +clflushopt -target-feature +xsave -target-feature +avx512vbmi2 -target-feature +64bit -target-feature +avx512vl -target-feature -serialize -target-feature -hreset -target-feature +invpcid -target-feature +avx512cd -target-feature +avx -target-feature +vaes -target-feature -amx-int8 -target-feature +cx8 -target-feature +fma -target-feature -rtm -target-feature +bmi -target-feature -enqcmd -target-feature +rdrnd -target-feature -mwaitx -target-feature +sse4.1 -target-feature +sse4.2 -target-feature +avx2 -target-feature +fxsr -target-feature +wbnoinvd -target-feature +sse -target-feature +lzcnt -target-feature +pclmul -target-feature -rdpru -target-feature -avxifma -target-feature +f16c -target-feature +ssse3 -target-feature +sgx -target-feature -prefetchwt1 -target-feature +cmov -target-feature +avx512vbmi -target-feature -shstk -target-feature +movbe -target-feature -avx512vp2intersect -target-feature +xsaveopt -target-feature +avx512dq -target-feature +sse2 -target-feature +adx -target-feature +sse3 -mllvm -treat-scalable-fixed-error-as-warning -debugger-tuning=gdb -v -Ofast -ferror-limit 19 -fopenmp -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o block_solver.o -x ir block_solver.orig.ll
```
`clang` invocation to reproduce _default cpu_ behavior:
```
clang -cc1 -triple x86_64-unknown-linux-gnu -emit-obj -disable-free -clear-ast-before-backend -main-file-name block_solver.ll -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -menable-no-infs -menable-no-nans -fapprox-func -funsafe-math-optimizations -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -mllvm -treat-scalable-fixed-error-as-warning -debugger-tuning=gdb -v -Ofast -ferror-limit 19 -fopenmp -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o block_solver.o -x ir block_solver.orig.ll
```
With `-march=native` the innermost loop is vectorized with runtime DD checks, but the vector loop is never executed because the trip count is small. The execution time is spent in the scalar portion of the loop. Here is the executed code in both cases:
<table>
<tr>
<td>W/o `-march=native` (fast):</td><td>With `-march=native` (slow):</td>
</tr>
<tr>
<td>
```
.LBB1_10: # Parent Loop BB1_2 Depth=1
# Parent Loop BB1_4 Depth=2
# Parent Loop BB1_6 Depth=3
# Parent Loop BB1_8 Depth=4
# => This Inner Loop Header: Depth=5
movsd (%rbx,%r8), %xmm1 # xmm1 = mem[0],zero
movhpd (%r14,%r8), %xmm1 # xmm1 = xmm1[0],mem[0]
movsd (%rbp,%r8), %xmm2 # xmm2 = mem[0],zero
movhpd (%rsi,%r8), %xmm2 # xmm2 = xmm2[0],mem[0]
movq 232(%rsp), %rcx # 8-byte Reload
movsd (%rcx,%r13,8), %xmm3 # xmm3 = mem[0],zero
movq 224(%rsp), %rcx # 8-byte Reload
movhpd (%rcx,%r13,8), %xmm3 # xmm3 = xmm3[0],mem[0]
movq 216(%rsp), %rcx # 8-byte Reload
movsd (%rcx,%r13,8), %xmm4 # xmm4 = mem[0],zero
movq 208(%rsp), %rcx # 8-byte Reload
movhpd (%rcx,%r13,8), %xmm4 # xmm4 = xmm4[0],mem[0]
movsd (%rax,%r8), %xmm5 # xmm5 = mem[0],zero
movq 200(%rsp), %rcx # 8-byte Reload
mulsd (%rcx,%r13,8), %xmm5
mulpd %xmm1, %xmm3
movsd (%rdx,%r8), %xmm1 # xmm1 = mem[0],zero
mulsd (%rdi,%r13,8), %xmm1
mulpd %xmm2, %xmm4
movsd (%r9,%r8), %xmm2 # xmm2 = mem[0],zero
mulsd (%r15,%r13,8), %xmm2
addpd %xmm3, %xmm4
addsd %xmm1, %xmm2
addsd %xmm5, %xmm2
addsd %xmm0, %xmm2
movapd %xmm4, %xmm0
unpckhpd %xmm4, %xmm0 # xmm0 = xmm0[1],xmm4[1]
addsd %xmm4, %xmm0
addsd %xmm2, %xmm0
movq 192(%rsp), %rcx # 8-byte Reload
movsd %xmm0, (%rcx,%r12,8)
addq $8, %r8
addq %r10, %r13
cmpq %r8, %r11
jne .LBB1_10
jmp .LBB1_11
```
</td>
<td>
```
.LBB1_32: # %scalar.ph
# Parent Loop BB1_3 Depth=1
# Parent Loop BB1_6 Depth=2
# Parent Loop BB1_9 Depth=3
# Parent Loop BB1_12 Depth=4
# => This Inner Loop Header: Depth=5
movq 376(%rsp), %r12 # 8-byte Reload
vmovsd (%r12,%r10,8), %xmm6 # xmm6 = mem[0],zero
vfmadd132sd (%r9,%r8), %xmm5, %xmm6 # xmm6 = (xmm6 * mem) + xmm5
vmovsd 8(%rbx,%r10,8), %xmm5 # xmm5 = mem[0],zero
vfmadd132sd (%r14,%r8), %xmm6, %xmm5 # xmm5 = (xmm5 * mem) + xmm6
movq 384(%rsp), %r12 # 8-byte Reload
vmovsd 8(%r12,%r10,8), %xmm6 # xmm6 = mem[0],zero
vfmadd132sd (%rdx,%r8), %xmm5, %xmm6 # xmm6 = (xmm6 * mem) + xmm5
movq 368(%rsp), %r12 # 8-byte Reload
vmovsd (%r12,%r10,8), %xmm5 # xmm5 = mem[0],zero
vfmadd132sd (%rbp,%r8), %xmm6, %xmm5 # xmm5 = (xmm5 * mem) + xmm6
vmovsd 8(%rax,%r10,8), %xmm6 # xmm6 = mem[0],zero
vfmadd132sd (%r13,%r8), %xmm5, %xmm6 # xmm6 = (xmm6 * mem) + xmm5
movq 400(%rsp), %r12 # 8-byte Reload
vmovsd 8(%r12,%r10,8), %xmm7 # xmm7 = mem[0],zero
vfmadd132sd (%r11,%r8), %xmm6, %xmm7 # xmm7 = (xmm7 * mem) + xmm6
vmovsd (%rdi,%r10,8), %xmm5 # xmm5 = mem[0],zero
vfmadd132sd (%r15,%r8), %xmm7, %xmm5 # xmm5 = (xmm5 * mem) + xmm7
movq -72(%rsp), %r12 # 8-byte Reload
movq %r10, %rcx
movq %rax, %r10
movq %rbx, %rax
movq %rdi, %rbx
movq 392(%rsp), %rdi # 8-byte Reload
vmovsd %xmm5, (%r12,%rdi,8)
movq %rbx, %rdi
movq %rax, %rbx
movq %r10, %rax
movq %rcx, %r10
movq 8(%rsp), %r12 # 8-byte Reload
incq %r10
addq %rsi, %r15
addq %rsi, %r11
addq %rsi, %r13
addq %rsi, %rbp
addq %rsi, %rdx
addq %rsi, %r14
addq %rsi, %r9
cmpq %r10, %r12
jne .LBB1_32
jmp .LBB1_11
```
</td>
</tr>
</table>
There is extra GPR code in the slow version, but this is not the reason of the slowness (though, I will create a separate issue for LSR).
It seems that the main issue is the long dependency chain of FMAs, moreover, it is a loop-carried one. I cleared `contract` fast-math flag from the instructions inside the loop and got **1.22x** speed-up (see [block_solver.nocontract.ll.gz](https://github.com/llvm/llvm-project/files/10514448/block_solver.nocontract.ll.gz) ). The generated code seems to have shorter critical path on FP side:
```
.LBB1_32: # %scalar.ph
# Parent Loop BB1_3 Depth=1
# Parent Loop BB1_6 Depth=2
# Parent Loop BB1_9 Depth=3
# Parent Loop BB1_12 Depth=4
# => This Inner Loop Header: Depth=5
movq 376(%rsp), %r12 # 8-byte Reload
vmovsd (%r12,%r10,8), %xmm6 # xmm6 = mem[0],zero
vmulsd (%r9,%r8), %xmm6, %xmm6
vmovsd 8(%rbx,%r10,8), %xmm7 # xmm7 = mem[0],zero
vmulsd (%r14,%r8), %xmm7, %xmm7
movq 384(%rsp), %r12 # 8-byte Reload
vmovsd 8(%r12,%r10,8), %xmm8 # xmm8 = mem[0],zero
vaddsd %xmm5, %xmm6, %xmm5
vmulsd (%rdx,%r8), %xmm8, %xmm6
vaddsd %xmm6, %xmm7, %xmm6
movq 368(%rsp), %r12 # 8-byte Reload
vmovsd (%r12,%r10,8), %xmm7 # xmm7 = mem[0],zero
vmulsd (%rbp,%r8), %xmm7, %xmm7
vmovsd 8(%rax,%r10,8), %xmm8 # xmm8 = mem[0],zero
vmulsd (%r13,%r8), %xmm8, %xmm8
vaddsd %xmm6, %xmm5, %xmm5
vaddsd %xmm7, %xmm8, %xmm6
movq 400(%rsp), %r12 # 8-byte Reload
vmovsd 8(%r12,%r10,8), %xmm7 # xmm7 = mem[0],zero
vmulsd (%r11,%r8), %xmm7, %xmm7
vaddsd %xmm7, %xmm6, %xmm6
vaddsd %xmm6, %xmm5, %xmm5
vmovsd (%rdi,%r10,8), %xmm6 # xmm6 = mem[0],zero
vmulsd (%r15,%r8), %xmm6, %xmm6
vaddsd %xmm6, %xmm5, %xmm5
movq -72(%rsp), %r12 # 8-byte Reload
movq %r10, %rcx
movq %rax, %r10
movq %rbx, %rax
movq %rdi, %rbx
movq 392(%rsp), %rdi # 8-byte Reload
vmovsd %xmm5, (%r12,%rdi,8)
movq %rbx, %rdi
movq %rax, %rbx
movq %r10, %rax
movq %rcx, %r10
movq 8(%rsp), %r12 # 8-byte Reload
incq %r10
addq %rsi, %r15
addq %rsi, %r11
addq %rsi, %r13
addq %rsi, %rbp
addq %rsi, %rdx
addq %rsi, %r14
addq %rsi, %r9
cmpq %r10, %r12
jne .LBB1_32
jmp .LBB1_11
```
Is there something `x86-isel` can do about this?
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsW1tz46jy_zTkpQuXhXzLQx4Se3J2qmbrPzW75-z_LYUQspkg0ACyPfn0p0CyY1vIcS5zah9WNZVRoGmavtE_UKi1Yqk4v0HjOzReXNHarbS5WT_RxxU14irT-c-bP1cchLU1hw21oLQTjOegFXxmXNJHDvOv_4bNihsObsUh44qtSmoewdTKQjJIZ1uwUm-48VQKmC4rIXkOG-FWgCZDXFLDVihdKOrEmqPJENYWNojca3ArYUFXTmg1QMMFGt42P_8M8wkLFKxQS8lBal2BW1G3m3e8mxaROQjlZyqpe3Ci5PZhzZmfp6gV87yhMLr0FJnU7PHBarnmZlCgyRCl7Yz-vfkXfk2mM8g1lChdJIjMVQbJ9Bp-IjKTiMwFIvPviMwfEblG6SLaTO4gmQ3BPwkcP7SlLztjbreIzLrNd61Qs4YTAbqtLuBRJXEuJHBJgf68hItvDpxOuKSBywjo06VcfLPndMhlFLiMgW7LC7iUSUfF48BgAvTnJQx8cxlZzCRwmQJ9upSLby7DYloWU-g8XOW5jvrX3s3BGVEB07Vy3kFV5v1WWOA_airBaRifBIawvtuHojZiKRSV8OXLf36Hz9-gMjqvffRmPz2ve0nVMoSBNk2klTqvJUfpLaDx3VEseF4DKQfLJzReIDJbOVdZHxzkHpH7pXCrOhswXSJyL-V69x-ujP7OmUPkvhCSW0Tuk-E4GaXJEJH7vgl2KkOTIduJKNRaMxpi1WkwvF1KT_7I-IquhTZ90RvYAmYsAez1KzlsZ5OHyQjX6lHpjcJSqHqLl6oGzEvhsM6-A86FpZnkuDCcA2aSU4OpdTjjhTYcZ5Q9cpUDLqlQ2C8YK1pyOFqnlIBLw2W7GlzqnEuoBANcCYYlX3MJpPlFWFwJDrgsDC05rrRQjhu_Uq18M1dBHKWxUIU9alBUWcAFrSqjt9jnOfA_LS04LqlbYZ9US_EUhPCUSuOwGeT4iRttg5DUWs0EdRz8kpmojGZUhvGAi5wrbUoqcVGFJpQuKsMtN2seWCEyP_odcFFUmGnlDGUOpYuCWtfMbHStcqGWO9a-Z_8ulHA7oZX8CbhkWllnaua0wVQKarkNq9sIlWPnVWBRuiCAHTVL7jCrahDNboWDPGbfVXDqasMB0_V2nJCq6PY4u5W5M4-dHkTu2DaZxNotXcU4ZWWMuJlaFCWNslpFm5lhKelOUZR0FCNfV0yWtfyR_4j1VqZgq02sJytFZBYmc15q7xfdEYVd2ozabl-r4qyIqAzTcoudkJFRhnq377bXQrmuHRG5WxZKRBepKxZjVLmNEfG1UO9YfQbLhKNy2eVX6nUuTFcEvBE5f5QxhltL15GpWo31uOtaRdbZDimquF82vT0jyy3uMU4zmVBudoZpo98eB2NaFaKrLO_IcpNFPKysGNvSPO-fsBtgO02ymMf6tBYV7bGO66JPh2W57Q6QmypGa_JKdJeAt7qH2nIeId9Q4arHiKtVhhfcsVXEmhFHaz1zMoro21o-iuaZ1te7ycF7heJMqzU33agKhi1kbVe6ivYGQ53xpmjiQeRuMspElGE7LrJsy42gUjxFksvKb1BRdkKtKxax3X4m1tcXTb-xTBK8rC-o2DbaHNsksHHRfSUrI37B1Q9WRkU3uVER5yu990UX5X1mkPT2RM1H19toe7G10WS-yZQWah0V2EY2GUTu5FMszYck5LfAiPryysRywHrbtycXyaSbY4JElqfRjmUkZ-yid-OiSmSlXp8PkIirr6yLFiqlXme9W_K6IqGytJz1x2pPHDcc4lnfWh53grzPn1LApQcOvizn1GHLqGxKbrHlOebG-JLP4g01SvgSPudZvVxyg13tG1C6WOYZ4DXg_2vLy2aMFKVwkFwDLnTFVVkBLpaqZnjNjRVaoXQxGhDvzQXTUhucC7pU2jrBLOA197WmeOJYal0dNVjpWdE8N9bvb4uHh3_N5w-_3f7n08Pir9tv9-Rhfv_54faP31G6SADrYzSgAW9BGIhBoTguvAATPeS8oLV0wKr64R8s9A8WOsVC29kETzxMqBUPDUuuuPFq_yf4zgZf-PlX_7mlW3EQSnFTauuaI0lhYS9ve-ZpauVEyWGxALbi7NEiMoesdmF4Q7wfq7hHq3zLWe14DhlntLbNSevBwZCwYEsq5QDgzxVvyUNe8PP43op7MhUGBrsaqLQJNLoIrX7GAcBv7cGq2_PhOTCd-4VBpt0KmPex52zS_EznwddQ-um5wRz9lqP001_hUDeuO0Rm3mnCiakfgMh9GLMf2692RGZW6k136G5y32BekO1oOcd2H3y5u0sekmE4GCMpAHylxiv0i7eS7yOw4FUI-6QZ0tJ1KUd7SnJC2aWd7GnTDm2XeranHh1Qo3SB0k-7MeF48LP30Gbcb5zmPove7seO27GlXtscwOsWkbHJtojM_cssHHXOAZHxtixPT679jKEZpQsoeYnGd8NwYDj3mfSZ9arK96yT0etZ-5dn3gcTxYWvojOQ-AzkNcJb8XrW_uW88D_CKX5KdpNUz8wN23aOkT33Gc5-Og7fuNQ0bzm1T6ONlhfbGTJJEZkfS51GRE7PauN5hh9AyOjD5PUqfpfA_uWMjo_kTib_Yz2PImKPLtfzcPa_1nO_wP7lIj0_a4bGU8k4Inxovlwvww_SSy0vs-O4M65qsk7IXwduekYb-Qcm1pj8ueiXPzknPzkw_xn5ry_Kf5fl1pj8ybhffnI8jub5gfxpr_w0zwP_Eyt1udlnbuML6Ya9dKVe02bjaETa0w2P6WpVscewxew0d0q_U-ZwF4FDNL5LGm228Zh0QvBYzP7pj-lIL91ul0qu-3api7Llid5OQo7sTN6MpHn-o1HJaLabaNYRvyUZm2RnDO87R1SsrPZUe07JSTh8Vzz8v6_-jnvLateTnAELsWr0snIzJbtyE5FxU7IPqtWxEC89fvRpmZh2StV3MJt0qtl3MLvulLvvYJaQTjn8Cm5t1Xx5udw-u6hIp9GaIiEvRcW6DYtd9iO7UBh2st9klwcmlyTVdVHSPE9SYvN2lWfS97h3FkRmbeNtmJFcAyJ30N0MdwuZnQKIyErGr9rse1bSAyMmvdM0SxlHljLpMeosWuBebtTZRVY99sR32renvPgAA--1MomWo0mnBPhA1x-fsn2n7_QAxA_wnVPT0zNh8MGmDwXTLzX9KF5xv930lwTItKul6Xu0lLxk-unxNI2WppebvlOI_3p_3hfNJ6p7gz9P46bH02jZ93rT7xgeF2xs208VQmhHf3xkst9odoS9TII1dvRdqjRe1ebirZ59FHvHPh5EOahyI9I-rykXlyhmv6a4ds8phnW1e0h1aa5_UTFCsUPJTgv89mQNWm_urfEPqJII1QlJegmjrLqEKt-el7mLOSNU1_2w5AC8kHO4JD3tfTsu6ZyS-4bjU_3jb1ObmwK-dYbCv75-218ThEsGqTewu9_Z3280H6cq3dx1GE7t8wWEH6G4tT5A3ErXy5Uf9xk2QkpghlPHgYLlFTX-tfkmvdAGvvzxDZHro89gPzuwnJe2-SLccy-pUO2Y9nZDarWEnFdc5Vyxn8BWnkQXcP_7bbiSKbXhet1-QO6ar82l1hVm1BgRPoLnA4DPEG4_eQ5oMtxf6U2G8HxzV0i6bL4xb26Imhu7cNsolBU539_AAFU5LLXzmRiR22RAyLZ5BVtxnuO6CtcdnHc-0VV6N_nHfag78kD7_vw0Ya-4bq-ewk0i3d8ZtUbQsKJrDnaljeMGmBFOMCqh8srRCu6_gtdC3xX1ISA-__TA5filTRcJ913adGFu_6VNF8Weu7SJwNR33tq8gD9fmabXR4d9lwKX15WvR-d9cUA6OXx9M858c-nYSPgC0pwevp6Yoxc5vs0cl9TJs-5iZxct9vB4dBwHQ2fV0wM5Z10TtlNFSu5ec7-MOj8OZU4jHv0Wf-lBlxF_iVv5HGZ8s5WPD9njUHF2-BpzkphrdLzkmHZ61iNOrNwPMP8OgPIkK8SB5BkrHwba9KJc9wqtHyviAgz6Qfm7B3p-zKJ-Dfp8F_SMUEUQ6Cugp09ufxP0-S7oGaGKINBXQE-AX4w-2-cFEPoK9Nml-hUA9PyMo7NivxmA9oNPeL4yOwtAG5wWoJjhYHXJ3UqopQdR29kEC8ulB1GMKsg10Ey3ABKl91f5TZpfp9f0it8kk-loOr0mY3K1uhlf89E1pXTKGWez0WxWzJJkls2ydHp9Pc0nV-KGDEk6TMh0OCTTlAyyvJj6vnE2Hk4SRtBoyEsq5MCjooE2y6uAGW8mw5SQK0kzLm34c2lCFN80gBIRgsaLK3MTkFRWLy0aDaWwzj5zccLJ8HfW_z_zKe7-91s0XsAfXz_NYf7132Q4nCByP0qGg2xD1-HzOrB1Fj5MpdIj0h2yElpd1UbevBrXBVE9sAtL-W8AAAD__0did8w">