Skip to content

Commit 9e01d89

Browse files
committed
fix: replace matmul intrinsic with f_mv3 in m_compute_levelset, remove -fno-inline workaround
The matmul() intrinsic inside ! declare target subroutines triggers ifx 2025.1.1 SPIR-V ICE #5633 when the subroutine is inlined into a target teams loop kernel. Manual 3x3 matvec (f_mv3) avoids the intrinsic entirely, allowing the GPU code path to compile at all opt levels without the -fno-inline workaround in CMakeLists.txt.
1 parent 94e4d4b commit 9e01d89

2 files changed

Lines changed: 32 additions & 29 deletions

File tree

CMakeLists.txt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -860,17 +860,6 @@ if (MFC_SIMULATION)
860860
target_compile_options(simulation PRIVATE -Oipa0)
861861
endif()
862862
endif()
863-
# ifx 2025.1.1 SPIR-V ICE (#5633) on m_compute_levelset: the backend segfaults
864-
# when declare-target geometry subroutines (s_sphere_levelset etc.) are inlined
865-
# into the target teams loop region. -fno-inline prevents the inlining; the calls
866-
# are resolved at SPIR-V link time via !$omp declare target, so GPU execution is
867-
# preserved. Tested: -O1/-O2/-O3 all ICE; only -O3 -fno-inline compiles cleanly.
868-
if (CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM" AND MFC_OpenMP)
869-
set_source_files_properties(
870-
"${CMAKE_BINARY_DIR}/fypp/simulation/m_compute_levelset.fpp.f90"
871-
PROPERTIES COMPILE_FLAGS "-fno-inline"
872-
)
873-
endif()
874863
endif()
875864

876865
if (MFC_POST_PROCESS)

src/simulation/m_compute_levelset.fpp

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ module m_compute_levelset
2020

2121
contains
2222

23+
!> 3x3 matrix-vector multiply; replaces the matmul() intrinsic which triggers an ifx 2025.1.1 SPIR-V ICE (#5633) when inlined
24+
!! into a target teams loop kernel via declare target.
25+
pure function f_mv3(M, v) result(w)
26+
27+
$:GPU_ROUTINE(parallelism='[seq]')
28+
29+
real(wp), intent(in) :: M(3, 3), v(3)
30+
real(wp) :: w(3)
31+
w(1) = M(1, 1)*v(1) + M(1, 2)*v(2) + M(1, 3)*v(3)
32+
w(2) = M(2, 1)*v(1) + M(2, 2)*v(2) + M(2, 3)*v(3)
33+
w(3) = M(3, 1)*v(1) + M(3, 2)*v(2) + M(3, 3)*v(3)
34+
35+
end function f_mv3
36+
2337
!> Dispatch level-set distance and normal computations for all ghost points based on patch geometry type
2438
impure subroutine s_apply_levelset(gps, num_gps)
2539

@@ -159,7 +173,7 @@ contains
159173
offset(:) = patch_ib(ib_patch_id)%centroid_offset(:)
160174

161175
xy_local = [x_cc(i) - center(1), y_cc(j) - center(2), 0._wp] ! get coordinate frame centered on IB
162-
xy_local = matmul(inverse_rotation, xy_local) ! rotate the frame into the IB's coordinate
176+
xy_local = f_mv3(inverse_rotation, xy_local) ! rotate the frame into the IB's coordinate
163177
xy_local = xy_local - offset ! airfoils are a patch that require a centroid offset
164178
165179
if (xy_local(2) >= 0._wp) then
@@ -209,7 +223,7 @@ contains
209223
if (f_approx_equal(dist, 0._wp)) then
210224
gp%levelset_norm = 0._wp
211225
else
212-
gp%levelset_norm = matmul(rotation, dist_vec(:))/dist ! convert the normal vector back to global grid coordinates
226+
gp%levelset_norm = f_mv3(rotation, dist_vec(:))/dist ! convert the normal vector back to global grid coordinates
213227
end if
214228
215229
end subroutine s_airfoil_levelset
@@ -244,7 +258,7 @@ contains
244258
z_min = -lz/2
245259
246260
xyz_local = [x_cc(i), y_cc(j), z_cc(l)] - center
247-
xyz_local = matmul(inverse_rotation, xyz_local) ! rotate the frame into the IB's coordinates
261+
xyz_local = f_mv3(inverse_rotation, xyz_local) ! rotate the frame into the IB's coordinates
248262
xyz_local = xyz_local - offset ! airfoils are a patch that require a centroid offset
249263

250264
if (xyz_local(2) >= 0._wp) then
@@ -299,13 +313,13 @@ contains
299313
else
300314
normal(3) = 1._wp
301315
end if
302-
gp%levelset_norm = matmul(rotation, normal)
316+
gp%levelset_norm = f_mv3(rotation, normal)
303317
else
304318
gp%levelset = dist_surf
305319
if (f_approx_equal(dist_surf, 0._wp)) then
306320
gp%levelset_norm = 0._wp
307321
else
308-
gp%levelset_norm = matmul(rotation, dist_vec(:)/dist_surf)
322+
gp%levelset_norm = f_mv3(rotation, dist_vec(:)/dist_surf)
309323
end if
310324
end if
311325

@@ -345,7 +359,7 @@ contains
345359

346360
! convert grid to local coordinates
347361
xy_local = [x_cc(i) - center(1), y_cc(j) - center(2), 0._wp]
348-
xy_local = matmul(inverse_rotation, xy_local)
362+
xy_local = f_mv3(inverse_rotation, xy_local)
349363

350364
side_dists(1) = bottom_left(1) - xy_local(1)
351365
side_dists(2) = top_right(1) - xy_local(1)
@@ -372,7 +386,7 @@ contains
372386
dist_vec(2) = side_dists(idx)/abs(side_dists(idx))
373387
end if
374388
! convert the normal vector back into the global coordinate system
375-
gp%levelset_norm = matmul(rotation, dist_vec)
389+
gp%levelset_norm = f_mv3(rotation, dist_vec)
376390
else
377391
gp%levelset_norm = 0._wp
378392
end if
@@ -408,13 +422,13 @@ contains
408422
ellipse_coeffs(2) = 0.5_wp*length_y
409423

410424
xy_local = [x_cc(i) - center(1), y_cc(j) - center(2), 0._wp]
411-
xy_local = matmul(inverse_rotation, xy_local)
425+
xy_local = f_mv3(inverse_rotation, xy_local)
412426

413427
normal_vector = xy_local
414428
! get the normal direction via the coordinate transformation method
415429
normal_vector(2) = normal_vector(2)*(ellipse_coeffs(1)/ellipse_coeffs(2))**2._wp
416430
normal_vector = normal_vector/sqrt(dot_product(normal_vector, normal_vector)) ! normalize the vector
417-
gp%levelset_norm = matmul(rotation, normal_vector) ! save after rotating the vector to the global frame
431+
gp%levelset_norm = f_mv3(rotation, normal_vector) ! save after rotating the vector to the global frame
418432

419433
! use the normal vector to set up the quadratic equation for the levelset, using A, B, and C in indices 1, 2, and 3
420434
quadratic_coeffs(1) = (normal_vector(1)/ellipse_coeffs(1))**2 + (normal_vector(2)/ellipse_coeffs(2))**2
@@ -467,7 +481,7 @@ contains
467481
Back = -length_z/2
468482

469483
xyz_local = [x_cc(i), y_cc(j), z_cc(k)] - center ! get coordinate frame centered on IB
470-
xyz_local = matmul(inverse_rotation, xyz_local) ! rotate the frame into the IB's coordinate
484+
xyz_local = f_mv3(inverse_rotation, xyz_local) ! rotate the frame into the IB's coordinate
471485
472486
dist_left = Left - xyz_local(1)
473487
dist_right = xyz_local(1) - Right
@@ -511,7 +525,7 @@ contains
511525
end if
512526
end if
513527
514-
gp%levelset_norm = matmul(rotation, dist_vec)
528+
gp%levelset_norm = f_mv3(rotation, dist_vec)
515529
516530
end subroutine s_cuboid_levelset
517531
@@ -600,7 +614,7 @@ contains
600614
end if
601615
602616
xyz_local = [x_cc(i), y_cc(j), z_cc(k)] - center ! get coordinate frame centered on IB
603-
xyz_local = matmul(inverse_rotation, xyz_local) ! rotate the frame into the IB's coordinates
617+
xyz_local = f_mv3(inverse_rotation, xyz_local) ! rotate the frame into the IB's coordinates
604618

605619
! get distance to flat edge of cylinder
606620
side_pos = dot_product(xyz_local, dist_sides_vec)
@@ -612,15 +626,15 @@ contains
612626
! if the closest edge is flat
613627
gp%levelset = -dist_side
614628
if (f_approx_equal(dist_side, abs(side_pos - boundary(1)))) then
615-
gp%levelset_norm = matmul(rotation, -dist_sides_vec)
629+
gp%levelset_norm = f_mv3(rotation, -dist_sides_vec)
616630
else
617-
gp%levelset_norm = matmul(rotation, dist_sides_vec)
631+
gp%levelset_norm = f_mv3(rotation, dist_sides_vec)
618632
end if
619633
else
620634
gp%levelset = dist_surface
621635
xyz_local = xyz_local*dist_surface_vec
622636
xyz_local = xyz_local/max(norm2(xyz_local), sgm_eps)
623-
gp%levelset_norm = matmul(rotation, xyz_local)
637+
gp%levelset_norm = f_mv3(rotation, xyz_local)
624638
end if
625639

626640
end subroutine s_cylinder_levelset
@@ -663,7 +677,7 @@ contains
663677
if (p > 0) then
664678
xyz_local(3) = z_cc(k) - center(3)
665679
end if
666-
xyz_local = matmul(inverse_rotation, xyz_local)
680+
xyz_local = f_mv3(inverse_rotation, xyz_local)
667681

668682
! 3D models
669683
if (p > 0) then
@@ -675,12 +689,12 @@ contains
675689
gp%levelset = -abs(gp%levelset)
676690

677691
! Assign the levelset_norm
678-
gp%levelset_norm = matmul(rotation, normals(1:3))
692+
gp%levelset_norm = f_mv3(rotation, normals(1:3))
679693
else
680694
! 2D models
681695
call s_distance_normals_2D(patch_id, boundary_edge_count, xyz_local, normals, distance)
682696
gp%levelset = -abs(distance)
683-
gp%levelset_norm = matmul(rotation, normals(1:3))
697+
gp%levelset_norm = f_mv3(rotation, normals(1:3))
684698
end if
685699

686700
end subroutine s_model_levelset

0 commit comments

Comments
 (0)