Hello, here is a fix for a wrong code issue, where we pass a descriptor with broken bounds when the actual argument is a transposed array and the dummy an assumed shape dummy. The bug comes from the interaction of the transpose optimization, which creates a descriptor with transposed bounds without copying the data, and the contiguous optimization, which reuses the descriptor for passing as argument after the call to internal_pack. The attached patch makes a copy of the descriptor with the correct bounds when a transposed scalarization is detected.
Regression-tested on x86_64-unknown-linux-gnu. This is not a regression as far as I know, but quite a severe wrong-code, albeit limited to the corner case of transpose and assumed shape and contiguous. OK for trunk/4.8/4.7 anyway ? Mikael PS: To not reproduce the same mistake as in the PR regarding the memory representation of matrices, I have filled the matrices one element at a time in the testcase.
2014-03-09 Mikael Morin <mik...@gcc.gnu.org> PR fortran/60392 * trans-array.c (gfc_conv_array_parameter): Don't reuse the descriptor if it has transposed dimensions. 2014-03-09 Mikael Morin <mik...@gcc.gnu.org> PR fortran/60392 * gfortran.dg/transpose_4.f90: New test. Index: trans-array.c =================================================================== --- trans-array.c (révision 208442) +++ trans-array.c (copie de travail) @@ -7227,7 +7227,50 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * else { tmp = build_fold_indirect_ref_loc (input_location, desc); - gfc_conv_descriptor_data_set (&se->pre, tmp, ptr); + + gfc_ss * ss = gfc_walk_expr (expr); + if (!transposed_dims (ss)) + gfc_conv_descriptor_data_set (&se->pre, tmp, ptr); + else + { + tree old_field, new_field; + + /* The original descriptor has transposed dims so we can't reuse + it directly; we have to create a new one. */ + tree old_desc = tmp; + tree new_desc = gfc_create_var (TREE_TYPE (old_desc), "arg_desc"); + + old_field = gfc_conv_descriptor_dtype (old_desc); + new_field = gfc_conv_descriptor_dtype (new_desc); + gfc_add_modify (&se->pre, new_field, old_field); + + old_field = gfc_conv_descriptor_offset (old_desc); + new_field = gfc_conv_descriptor_offset (new_desc); + gfc_add_modify (&se->pre, new_field, old_field); + + for (int i = 0; i < expr->rank; i++) + { + old_field = gfc_conv_descriptor_dimension (old_desc, + gfc_rank_cst[get_array_ref_dim_for_loop_dim (ss, i)]); + new_field = gfc_conv_descriptor_dimension (new_desc, + gfc_rank_cst[i]); + gfc_add_modify (&se->pre, new_field, old_field); + } + + if (gfc_option.coarray == GFC_FCOARRAY_LIB + && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (old_desc)) + && GFC_TYPE_ARRAY_AKIND (TREE_TYPE (old_desc)) + == GFC_ARRAY_ALLOCATABLE) + { + old_field = gfc_conv_descriptor_token (old_desc); + new_field = gfc_conv_descriptor_token (new_desc); + gfc_add_modify (&se->pre, new_field, old_field); + } + + gfc_conv_descriptor_data_set (&se->pre, new_desc, ptr); + se->expr = gfc_build_addr_expr (NULL_TREE, new_desc); + } + gfc_free_ss (ss); } if (gfc_option.rtcheck & GFC_RTCHECK_ARRAY_TEMPS)
! { dg-do run } ! ! PR fortran/60392 ! In the transposed case call to my_mul_cont, the compiler used to (wrongly) ! reuse a transposed descriptor for an array that was not transposed as a result ! of packing. ! ! Original test case from Alexander Vogt <a.v...@fulguritus.com>. program test implicit none integer, dimension(2,2) :: A, R, RT integer, dimension(2,2) :: B1, B2 ! ! A = [ 2 17 ] ! [ 82 257 ] ! ! matmul(a,a) = [ 1398 4403 ] ! [ 21238 67443 ] ! ! matmul(transpose(a), a) = [ 6728 21108 ] ! [ 21108 66338 ] A(1,1) = 2 A(1,2) = 17 A(2,1) = 82 A(2,2) = 257 R(1,1) = 1398 R(1,2) = 4403 R(2,1) = 21238 R(2,2) = 67443 RT(1,1) = 6728 RT(1,2) = 21108 RT(2,1) = 21108 RT(2,2) = 66338 ! Normal argument B1 = 0 B2 = 0 B1 = my_mul(A,A) B2 = my_mul_cont(A,A) ! print *,'Normal: ',maxval(abs(B1-B2)) ! print *,B1 ! print *,B2 if (any(B1 /= R)) call abort if (any(B2 /= R)) call abort ! Transposed argument B1 = 0 B2 = 0 B1 = my_mul(transpose(A),A) B2 = my_mul_cont(transpose(A),A) ! print *,'Transposed:',maxval(abs(B1-B2)) ! print *,B1 ! print *,B2 if (any(B1 /= RT)) call abort if (any(B2 /= RT)) call abort contains function my_mul(A,C) result (B) use, intrinsic :: ISO_Fortran_env integer, intent(in) :: A(2,2), C(2,2) integer :: B(2,2) B = matmul(A, C) end function function my_mul_cont(A,C) result (B) use, intrinsic :: ISO_Fortran_env integer, intent(in), contiguous :: A(:,:), C(:,:) integer :: B(2,2) B = matmul(A, C) end function end program