Using much smaller sizes
julia> Nt = 400; Nx = 120;
julia> @btime foo1!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
165.522 μs (0 allocations: 0 bytes)
julia> @btime foo2!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
184.462 μs (0 allocations: 0 bytes)
julia> @btime foo1_inbounds!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
42.759 μs (0 allocations: 0 bytes)
julia> @btime foo2_inbounds!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
45.094 μs (0 allocations: 0 bytes)
julia> @btime foo1_fm!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
27.266 μs (0 allocations: 0 bytes)
julia> @btime foo2_fm!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
26.341 μs (0 allocations: 0 bytes)
julia> @btime foo1_turbo!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
18.326 μs (0 allocations: 0 bytes)
julia> @btime foo2_turbo!(m, dt, C, C2, Nt, Nx) setup = (dt=0.125; C=0.3; C2=C^2; Nt=$Nt; Nx=$Nx; m=rand(Nx,Nt+1);)
19.072 μs (0 allocations: 0 bytes)
FWIW, assembly of the @turbo
versions, foo1:
.LBB0_3: # %L84
# Parent Loop BB0_2 Depth=1
# => This Inner Loop Header: Depth=2
vmovupd zmm10, zmmword ptr [rbp + 8*r15 - 152]
vmovupd zmm11, zmmword ptr [rbp + 8*r15 - 144]
vmovupd zmm12, zmmword ptr [rbp + 8*r15 - 128]
vmovupd zmm13, zmmword ptr [rbp + 8*r15 - 88]
vmovupd zmm14, zmmword ptr [rbp + 8*r15 - 24]
vaddpd zmm10, zmm10, zmmword ptr [rbp + 8*r15 - 136]
vaddpd zmm13, zmm13, zmmword ptr [rbp + 8*r15 - 72]
vaddpd zmm14, zmm14, zmmword ptr [rbp + 8*r15 - 8]
vmovupd zmm15, zmmword ptr [rbp + 8*r15 - 80]
vmovupd zmm16, zmmword ptr [rbp + 8*r15 - 16]
vmovupd zmm17, zmmword ptr [rbp + 8*r15 - 64]
vmovupd zmm18, zmmword ptr [rbp + 8*r15]
vaddpd zmm12, zmm12, zmmword ptr [rbp + 8*r15 - 160]
vaddpd zmm17, zmm17, zmmword ptr [rbp + 8*r15 - 96]
vaddpd zmm18, zmm18, zmmword ptr [rbp + 8*r15 - 32]
vfmadd231pd zmm12, zmm11, zmm2 # zmm12 = (zmm11 * zmm2) + zmm12
vfmadd231pd zmm17, zmm15, zmm2 # zmm17 = (zmm15 * zmm2) + zmm17
vfmadd231pd zmm18, zmm16, zmm2 # zmm18 = (zmm16 * zmm2) + zmm18
vfnmadd231pd zmm12, zmm3, zmm10 # zmm12 = -(zmm3 * zmm10) + zmm12
vfnmadd231pd zmm17, zmm3, zmm13 # zmm17 = -(zmm3 * zmm13) + zmm17
vfnmadd231pd zmm18, zmm3, zmm14 # zmm18 = -(zmm3 * zmm14) + zmm18
vmovupd zmm10, zmmword ptr [rcx + 8*r15 - 128]
vmovupd zmm13, zmmword ptr [rcx + 8*r15 - 64]
vmovupd zmm14, zmmword ptr [rcx + 8*r15]
vfmadd213pd zmm10, zmm4, zmmword ptr [r13 + 8*r15 + 16] # zmm10 = (zmm4 * zmm10) + mem
vfmadd213pd zmm13, zmm4, zmmword ptr [r13 + 8*r15 + 80] # zmm13 = (zmm4 * zmm13) + mem
vfmadd213pd zmm14, zmm4, zmmword ptr [r13 + 8*r15 + 144] # zmm14 = (zmm4 * zmm14) + mem
vfmadd231pd zmm10, zmm5, zmmword ptr [rbx + 8*r15 - 128] # zmm10 = (zmm5 * mem) + zmm10
vfmadd231pd zmm13, zmm5, zmmword ptr [rbx + 8*r15 - 64] # zmm13 = (zmm5 * mem) + zmm13
vfmadd231pd zmm14, zmm5, zmmword ptr [rbx + 8*r15] # zmm14 = (zmm5 * mem) + zmm14
vfmadd231pd zmm10, zmm6, zmm11 # zmm10 = (zmm6 * zmm11) + zmm10
vfmadd231pd zmm13, zmm6, zmm15 # zmm13 = (zmm6 * zmm15) + zmm13
vfmadd231pd zmm14, zmm6, zmm16 # zmm14 = (zmm6 * zmm16) + zmm14
vmulpd zmm10, zmm10, zmm9
vmulpd zmm11, zmm13, zmm7
vmulpd zmm13, zmm14, zmm7
vfmsub231pd zmm10, zmm0, zmm12 # zmm10 = (zmm0 * zmm12) - zmm10
vfmsub231pd zmm11, zmm0, zmm17 # zmm11 = (zmm0 * zmm17) - zmm11
vfmsub231pd zmm13, zmm0, zmm18 # zmm13 = (zmm0 * zmm18) - zmm13
vfmsub231pd zmm10, zmm1, zmm8 # zmm10 = (zmm1 * zmm8) - zmm10
vfmsub231pd zmm11, zmm1, zmm8 # zmm11 = (zmm1 * zmm8) - zmm11
vfmsub231pd zmm13, zmm1, zmm8 # zmm13 = (zmm1 * zmm8) - zmm13
vmovupd zmmword ptr [rax + 8*r15 - 128], zmm10
vmovupd zmmword ptr [rax + 8*r15 - 64], zmm11
vmovupd zmmword ptr [rax + 8*r15], zmm13
add r15, 24
cmp r15, rsi
jle .LBB0_3
foo2:
.LBB0_3: # %L82
# Parent Loop BB0_2 Depth=1
# => This Inner Loop Header: Depth=2
vmovupd zmm12, zmmword ptr [rcx + 8*r15 - 80]
vmovupd zmm13, zmmword ptr [rcx + 8*r15 - 16]
vmovupd zmm14, zmmword ptr [rcx + 8*r15 - 152]
vmovupd zmm15, zmmword ptr [rcx + 8*r15 - 144]
vmovupd zmm16, zmmword ptr [rcx + 8*r15 - 128]
vmovupd zmm17, zmmword ptr [rcx + 8*r15 - 88]
vmovupd zmm18, zmmword ptr [rcx + 8*r15 - 24]
vaddpd zmm14, zmm14, zmmword ptr [rcx + 8*r15 - 136]
vaddpd zmm17, zmm17, zmmword ptr [rcx + 8*r15 - 72]
vaddpd zmm18, zmm18, zmmword ptr [rcx + 8*r15 - 8]
vmovupd zmm19, zmmword ptr [rcx + 8*r15 - 64]
vmovupd zmm20, zmmword ptr [rcx + 8*r15]
vaddpd zmm16, zmm16, zmmword ptr [rcx + 8*r15 - 160]
vaddpd zmm19, zmm19, zmmword ptr [rcx + 8*r15 - 96]
vaddpd zmm20, zmm20, zmmword ptr [rcx + 8*r15 - 32]
vfmadd231pd zmm16, zmm15, zmm2 # zmm16 = (zmm15 * zmm2) + zmm16
vfmadd231pd zmm19, zmm12, zmm2 # zmm19 = (zmm12 * zmm2) + zmm19
vfmadd231pd zmm20, zmm13, zmm2 # zmm20 = (zmm13 * zmm2) + zmm20
vfnmadd231pd zmm16, zmm3, zmm14 # zmm16 = -(zmm3 * zmm14) + zmm16
vfnmadd231pd zmm19, zmm3, zmm17 # zmm19 = -(zmm3 * zmm17) + zmm19
vfnmadd231pd zmm20, zmm3, zmm18 # zmm20 = -(zmm3 * zmm18) + zmm20
vfmsub213pd zmm16, zmm0, zmmword ptr [r13 + 8*r15 + 16] # zmm16 = (zmm0 * zmm16) - mem
vfmsub213pd zmm19, zmm0, zmmword ptr [r13 + 8*r15 + 80] # zmm19 = (zmm0 * zmm19) - mem
vfmsub213pd zmm20, zmm0, zmmword ptr [r13 + 8*r15 + 144] # zmm20 = (zmm0 * zmm20) - mem
vfnmadd231pd zmm16, zmm1, zmm4 # zmm16 = -(zmm1 * zmm4) + zmm16
vfnmadd231pd zmm19, zmm1, zmm4 # zmm19 = -(zmm1 * zmm4) + zmm19
vfnmadd231pd zmm20, zmm1, zmm4 # zmm20 = -(zmm1 * zmm4) + zmm20
vfnmadd231pd zmm16, zmm5, zmmword ptr [rbp + 8*r15 - 128] # zmm16 = -(zmm5 * mem) + zmm16
vfnmadd231pd zmm19, zmm5, zmmword ptr [rbp + 8*r15 - 64] # zmm19 = -(zmm5 * mem) + zmm19
vfnmadd231pd zmm20, zmm5, zmmword ptr [rbp + 8*r15] # zmm20 = -(zmm5 * mem) + zmm20
vfnmadd231pd zmm16, zmm6, zmmword ptr [rbx + 8*r15 - 128] # zmm16 = -(zmm6 * mem) + zmm16
vfnmadd231pd zmm19, zmm6, zmmword ptr [rbx + 8*r15 - 64] # zmm19 = -(zmm6 * mem) + zmm19
vfnmadd231pd zmm20, zmm6, zmmword ptr [rbx + 8*r15] # zmm20 = -(zmm6 * mem) + zmm20
vfmsub231pd zmm16, zmm7, zmm15 # zmm16 = (zmm7 * zmm15) - zmm16
vmulpd zmm14, zmm16, zmm11
vfmsub231pd zmm19, zmm7, zmm12 # zmm19 = (zmm7 * zmm12) - zmm19
vfmsub231pd zmm20, zmm7, zmm13 # zmm20 = (zmm7 * zmm13) - zmm20
vmulpd zmm12, zmm19, zmm9
vmulpd zmm13, zmm20, zmm9
vmovupd zmmword ptr [rax + 8*r15 - 128], zmm14
vmovupd zmmword ptr [rax + 8*r15 - 64], zmm12
vmovupd zmmword ptr [rax + 8*r15], zmm13
add r15, 24
cmp r15, rsi
jle .LBB0_3
Assembly doesn’t look strikingly different. No divisions, it’s been replaced with multiplication by the inverse.
Both versions require 10 arithmetic instructions, a mix of adds, fmas, and multiplies.
I have an M1 at home, so I can take a look later.