Iāve tried a slightly different code (with res used as the function result):
function associate_fn(x) result(res)
implicit none
integer, intent(in) :: x
integer :: res
associate(point => x)
res = point+point
end associate
end function
function pointer_fn(x) result(res)
implicit none
integer, target, intent(in) :: x
integer :: res
integer, pointer :: point
point => x
res = point+point
end function
Then, the output of CompilerExplorer was something like this:
=== gfortran-15.2 (no option) ===
associate_fn_:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -24(%rbp)
movq -24(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
addl %eax, %eax
movl %eax, -12(%rbp)
movl -12(%rbp), %eax
popq %rbp
ret
pointer_fn_:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -24(%rbp)
movq -24(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
addl %eax, %eax
movl %eax, -12(%rbp)
movl -12(%rbp), %eax
popq %rbp
ret
=== gfortran-15.2 -O2 ===
associate_fn_:
movl (%rdi), %eax
addl %eax, %eax
ret
pointer_fn_:
movl (%rdi), %eax
addl %eax, %eax
ret
=== ifx-2025.3.2 (no option) ===
associate_fn_:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -80(%rbp)
movq -80(%rbp), %rcx
movl (%rcx), %eax
addl (%rcx), %eax
movl %eax, -68(%rbp)
movl -68(%rbp), %eax
popq %rbp
retq
pointer_fn_:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -80(%rbp)
movq -80(%rbp), %rax
movq %rax, -88(%rbp)
movq -88(%rbp), %rax
movl (%rax), %eax
movq -88(%rbp), %rcx
addl (%rcx), %eax
movl %eax, -68(%rbp)
movl -68(%rbp), %eax
popq %rbp
retq
=== ifx-2025.3.2 -O2 ===
associate_fn_:
movl (%rdi), %eax
addl %eax, %eax
retq
pointer_fn_:
movl (%rdi), %eax
addl %eax, %eax
retq
=== Lfortran-0.59 (no option) ===
associate_fn:
movq %rdi, -8(%rsp)
movl (%rdi), %eax
addl %eax, %eax
movl %eax, -12(%rsp)
retq
pointer_fn:
movq %rdi, -8(%rsp)
movl (%rdi), %eax
addl %eax, %eax
movl %eax, -12(%rsp)
retq
=== Lfortran-0.59 -O2 ===
associate_fn:
movq %rdi, -8(%rsp)
movl (%rdi), %eax
addl %eax, %eax
movl %eax, -12(%rsp)
retq
pointer_fn:
movq %rdi, -8(%rsp)
movl (%rdi), %eax
addl %eax, %eax
movl %eax, -12(%rsp)
retq
=== flang-20.18 (no option) ===
associate_fn_:
pushq %rbp
movq %rsp, %rbp
movl (%rdi), %eax
addl %eax, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
retq
pointer_fn_:
pushq %rbp
movq %rsp, %rbp
movb $0, -57(%rbp)
movb $1, -58(%rbp)
movb $9, -59(%rbp)
movb $0, -60(%rbp)
movl $20240719, -64(%rbp)
movq $4, -72(%rbp)
movq $0, -80(%rbp)
movq -64(%rbp), %rax
movq %rax, -96(%rbp)
movups -80(%rbp), %xmm0
movaps %xmm0, -112(%rbp)
movq %rdi, -48(%rbp)
movb $0, -25(%rbp)
movb $1, -26(%rbp)
movb $9, -27(%rbp)
movb $0, -28(%rbp)
movl $20240719, -32(%rbp)
movq $4, -40(%rbp)
movq -48(%rbp), %rax
movq %rax, -112(%rbp)
movq -40(%rbp), %rax
movq %rax, -104(%rbp)
movq -32(%rbp), %rax
movq %rax, -96(%rbp)
movq -112(%rbp), %rax
movq %rax, -24(%rbp)
movq -104(%rbp), %rax
movq %rax, -16(%rbp)
movq -96(%rbp), %rax
movq %rax, -8(%rbp)
movq -24(%rbp), %rax
movl (%rax), %eax
addl %eax, %eax
movl %eax, -52(%rbp)
movl -52(%rbp), %eax
popq %rbp
retq
=== flang-20.18 -O2 ===
associate_fn_:
movl (%rdi), %eax
addl %eax, %eax
retq
pointer_fn_:
movl (%rdi), %eax
addl %eax, %eax
retq
So, if I look only at the number of lines, it seems (for this simple code):
- With no option, the pointer version often requires more lines;
- With -O2, both the functions become identical in the assembly output;
- With -O2, Gfortran, ifx, and flang use only 2 lines for both the functions, while Lfortran uses 4 lines for some reason;
- With no option, Flang gives a very long assembly code for the pointer version for some reason (but it is reduced to 2 lines with -O2)
EDIT: My main message above is that āthe assembly output changes depending on -O2ā, rather than āASSOCIATE behaves the same way as raw pointersā etc⦠(I felt interesting to see how compilers can optimize code into a very short one at the assembly level.)