https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128431
Richard Biener <rguenth at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
See Also| |https://gcc.gnu.org/bugzill
| |a/show_bug.cgi?id=126079
Status|UNCONFIRMED |NEW
Ever confirmed|0 |1
Last reconfirmed| |2026-11-04
--- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Thomas Koenig from comment #0)
> This is on rocketlake.
>
> The following code
>
> subroutine foo (from_small, to_small, from_buf, to_buf)
> implicit none
> unsigned(8), value :: from_small, to_small
> unsigned(1), dimension(41), intent(out) :: from_buf, to_buf
> integer, parameter :: grpsz = 6, tabsz=729
> integer :: i, k
> unsigned(16), parameter :: base = 3u_16
> integer, parameter :: n_grp = int(64 * log(2.0)/log(real(base)) / grpsz) !
> rounding down
> integer, parameter :: halfsize = n_grp * grpsz
>
> unsigned(kind=1), dimension(0:grpsz-1,0:tabsz-1), parameter :: tab =
> reshape ([ &
> ((mod(uint(k)/base**uint(i), base), i=0, grpsz-1), k=0, tabsz-1) &
> ], shape = [grpsz,tabsz])
> unsigned, parameter :: tabszu = uint(tabsz)
> unsigned(8) :: from_rem, to_rem
> do i=0, halfsize-1, grpsz
> to_rem = mod(to_small, tabszu)
> to_small = to_small / tabszu
> from_rem = mod(from_small, tabszu)
> from_small = mod(from_small, tabszu)
> to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> end do
> end subroutine foo
>
> yields some weird assembly code with
>
> gfortran -fverbose-asm -march=native -mtune=native -fmax-errors=1 -funsigned
> -S -O3 tst2.f90
>
> (only weird parts copied):
>
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> vmovd %edx, %xmm0 # tab[_125], tmp377
> movzbl tab.0+2(%rbx), %edx # tab[_94], tab[_94]
> vpinsrb $1, tab.0+1(%rbx), %xmm0, %xmm0 #, tab[_102], tmp377, tmp378
> vmovd %edx, %xmm7 # tab[_94], tmp383
> movzbl tab.0+4(%rbx), %edx # tab[_70], tab[_70]
> vpinsrb $1, tab.0+3(%rbx), %xmm7, %xmm7 #, tab[_87], tmp383, tmp384
> vmovd %edx, %xmm3 # tab[_70], tmp389
> movzbl tab.0(%r11), %edx # tab[_69], tab[_69]
> vpinsrb $1, tab.0+5(%rbx), %xmm3, %xmm3 #, tab[_41], tmp389, tmp390
> vpunpcklwd %xmm7, %xmm0, %xmm0 # tmp384, tmp378, tmp423
> vmovd %edx, %xmm6 # tab[_69], tmp395
> movzbl tab.0+2(%r11), %edx # tab[_133], tab[_133]
> vpinsrb $1, tab.0+1(%r11), %xmm6, %xmm6 #, tab[_77], tmp395, tmp396
> vmovd %edx, %xmm1 # tab[_133], tmp401
> movzbl tab.0+4(%r11), %edx # tab[_141], tab[_141]
> vpinsrb $1, tab.0+3(%r11), %xmm1, %xmm1 #, tab[_137], tmp401, tmp402
> vpunpcklwd %xmm6, %xmm3, %xmm3 # tmp396, tmp390, tmp425
> vmovd %edx, %xmm5 # tab[_141], tmp407
> vpunpckldq %xmm3, %xmm0, %xmm0 # tmp425, tmp423, tmp431
> vpinsrb $1, tab.0+5(%r11), %xmm5, %xmm5 #, tab[_145], tmp407, tmp408
> movzbl tab.0(%r10), %edx # tab[_179], tab[_179]
> vmovd %edx, %xmm2 # tab[_179], tmp413
> movzbl tab.0+2(%r10), %edx # tab[_187], tab[_187]
> vpunpcklwd %xmm5, %xmm1, %xmm1 # tmp408, tmp402, tmp427
> vpinsrb $1, tab.0+1(%r10), %xmm2, %xmm2 #, tab[_183], tmp413, tmp414
> vmovd %edx, %xmm4 # tab[_187], tmp419
> movzbl tab.0+4(%r10), %edx # tab[_195], tab[_195]
> vpinsrb $1, tab.0+3(%r10), %xmm4, %xmm4 #, tab[_191], tmp419, tmp420
> vpunpcklwd %xmm4, %xmm2, %xmm2 # tmp420, tmp414, tmp429
> vpunpckldq %xmm2, %xmm1, %xmm1 # tmp429, tmp427, tmp433
> vpunpcklqdq %xmm1, %xmm0, %xmm0 # tmp433, tmp431, tmp435
> vmovd %edx, %xmm1 # tab[_195], tmp438
> movzbl tab.0(%r9), %edx # tab[_233], tab[_233]
> vpinsrb $1, tab.0+5(%r10), %xmm1, %xmm1 #, tab[_199], tmp438, tmp439
> vmovd %edx, %xmm8 # tab[_233], tmp444
> movzbl tab.0+2(%r9), %edx # tab[_241], tab[_241]
> vpinsrb $1, tab.0+1(%r9), %xmm8, %xmm8 #, tab[_237], tmp444, tmp445
> vmovd %edx, %xmm4 # tab[_241], tmp450
> movzbl tab.0+4(%r9), %edx # tab[_249], tab[_249]
> vpinsrb $1, tab.0+3(%r9), %xmm4, %xmm4 #, tab[_245], tmp450, tmp451
> vpunpcklwd %xmm8, %xmm1, %xmm1 # tmp445, tmp439, tmp484
> vmovd %edx, %xmm7 # tab[_249], tmp456
> movzbl tab.0(%r8), %edx # tab[_287], tab[_287]
> vpinsrb $1, tab.0+5(%r9), %xmm7, %xmm7 #, tab[_253], tmp456, tmp457
> vmovd %edx, %xmm2 # tab[_287], tmp462
> movzbl tab.0+2(%r8), %edx # tab[_295], tab[_295]
> vpinsrb $1, tab.0+1(%r8), %xmm2, %xmm2 #, tab[_291], tmp462, tmp463
> vpunpcklwd %xmm7, %xmm4, %xmm4 # tmp457, tmp451, tmp486
> vmovd %edx, %xmm6 # tab[_295], tmp468
> movzbl tab.0+4(%r8), %edx # tab[_303], tab[_303]
> vpunpckldq %xmm4, %xmm1, %xmm1 # tmp486, tmp484, tmp492
> vpinsrb $1, tab.0+3(%r8), %xmm6, %xmm6 #, tab[_299], tmp468, tmp469
> vmovd %edx, %xmm3 # tab[_303], tmp474
> movzbl tab.0(%rcx), %edx # tab[_26], tab[_26]
> vpinsrb $1, tab.0+5(%r8), %xmm3, %xmm3 #, tab[_307], tmp474, tmp475
> vpunpcklwd %xmm6, %xmm2, %xmm2 # tmp469, tmp463, tmp488
> vmovd %edx, %xmm5 # tab[_26], tmp480
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> movl tab.0+2(%rcx), %edx # MEM <vector(4) unsigned(kind=1)>
> [(unsigned(kind=1) *)vectp.12_206], vect__106.13_207
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> vpinsrb $1, tab.0+1(%rcx), %xmm5, %xmm5 #, tab[_95], tmp480, tmp481
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> movl %edx, 31(%r14) # vect__106.13_207, MEM <vector(4)
> unsigned(kind=1)>
> [(unsigned(kind=1) *)to_buf_27(D) + 31B]
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> vpunpcklwd %xmm5, %xmm3, %xmm3 # tmp481, tmp475, tmp490
> vpunpckldq %xmm3, %xmm2, %xmm2 # tmp490, tmp488, tmp494
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> vmovd %r12d, %xmm3 # _4, tmp512
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> vpunpcklqdq %xmm2, %xmm1, %xmm1 # tmp494, tmp492, tmp496
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> vpinsrb $1, tab.0+5(%rdi), %xmm3, %xmm3 #, tab[_2], tmp512, tmp513
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> vinserti32x4 $0x1, %xmm1, %ymm0, %ymm0 # tmp496, tmp435, _202
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> vmovd %esi, %xmm1 # _14, tmp508
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> movl -4(%rsp), %esi # %sfp, MEM <vector(4) unsigned(kind=1)>
> [(unsigned(kind=1) *)vectp.19_218]
> # tst2.f90:21: to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
> vmovdqu %ymm0, -1(%r14) # _202, MEM <vector(32) unsigned(kind=1)>
> [(unsigned(kind=1) *)to_buf_27(D) + -1B]
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> vmovd %eax, %xmm0 # _34, tmp504
> vpinsrb $1, tab.0+3(%rdi), %xmm1, %xmm1 #, tab[_8], tmp508, tmp509
> vpinsrb $1, tab.0+1(%rdi), %xmm0, %xmm0 #, tab[_29], tmp504, tmp505
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> movl %esi, 31(%r13) # MEM <vector(4) unsigned(kind=1)>
> [(unsigned(kind=1)
> *)vectp.19_218], MEM <vector(4) unsigned(kind=1)> [(unsigned(kind=1)
> *)from_buf_32(D) + 31B]
> # tst2.f90:22: from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
> vpunpcklwd %xmm1, %xmm0, %xmm2 # tmp509, tmp505, tmp535
> vpunpcklwd %xmm3, %xmm1, %xmm1 # tmp513, tmp509, tmp539
> vpunpcklwd %xmm0, %xmm3, %xmm0 # tmp505, tmp513, tmp537
> vpunpckldq %xmm0, %xmm2, %xmm3 # tmp537, tmp535, tmp543
> vpunpckldq %xmm2, %xmm1, %xmm2 # tmp535, tmp539, tmp545
> vpunpckldq %xmm1, %xmm0, %xmm0 # tmp539, tmp537, tmp588
> vpunpcklqdq %xmm2, %xmm3, %xmm2 # tmp545, tmp543, tmp547
> vpunpcklqdq %xmm3, %xmm0, %xmm0 # tmp543, tmp588, tmp592
> vinserti32x4 $0x1, %xmm0, %ymm2, %ymm0 # tmp592, tmp547, _213
> vmovdqu %ymm0, -1(%r13) # _213, MEM <vector(32) unsigned(kind=1)>
> [(unsigned(kind=1) *)from_buf_32(D) + -1B]
> vzeroupper
>
> The line
>
> to_buf (i:i+grpsz-1) = tab(:,int(to_rem))
>
> is a six-byte contiguous copy, which should be done with a a four-byte and a
> two-byte load and subsequent store.
The vectorizer does exactly that. The code you quite is from the
vectorization of
from_buf (i:i+grpsz-1) = tab(:,int(from_rem))
after completely unrolling the loop:
t.f90:21:46: optimized: basic block part vectorized using 4 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 2 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 4 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 2 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 4 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 2 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 4 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 2 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 4 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 2 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 4 byte vectors
t.f90:21:46: optimized: basic block part vectorized using 2 byte vectors
t.f90:22:50: optimized: basic block part vectorized using 32 byte vectors
t.f90:22:50: optimized: basic block part vectorized using 4 byte vectors
for the earlier block we split the store group because the loads are
from different interleaving chains (aliasing issue likely), where the
latter block is successfully handled with a repeating load permutation
but then
t.f90:22:50: note: ==> examining statement: _34 = tab[_37];
t.f90:22:50: missed: BB vectorization with gaps at the end of a load is not
supported
t.f90:22:50: missed: not vectorized: relevant stmt not supported: _34 =
tab[_37];
t.f90:22:50: note: Building vector operands of 0x282b4070 from scalars
instead
and that costs OK. This late failure isn't handled via splitting the
graph.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126079