= Fortran Translation Issues = == 1. Fortran Array Section Transformation == The pattern of transforming instances with Fortran array type and related operations: === 1.1 Fortran Array Declaration (and destruction) === {{{ INTEGER A(L2:H2:S2, L1:H1:S1) }}} => {{{ f_arr A = f_arr_create( // Create an f_arr instance for int array A sizeof(int), // 1. The size of each element 2, // 2. The number of dimensions (int[3][2]){ // 3. Dimension info in col-major order. {L2, L1}, // Lower-bounds for each dim. {H2, H1}, // Upper-bounds for each dim. {S2, S1}. // The idx-step for each dim. } ); }}} Each `f_arr` typed instance requires a destruction: {{{ f_arr_destroy(A); }}} === 1.2 Fortran Array Subscription === {{{ A(J, I) = A(J,I) - 1 }}} => {{{ *((int*)f_arr_subscript(A, (int[2]){J, I})) = *((int*) // Conversion from void* to element type f_arr_subscript( // Access the array elem. A(J, I) A, // 1. The array identifier (int[2]){J, I}) // 2. The sequence of indexes in col-major ) - 1 }}} === 1.3 Fortran Array Section === {{{ ... ! A section of array A is passed in. CALL UPDATE(A(L2+X:H2-Y:S2*Z, K)) ! A full array B is passed in CALL UPDATE(B) ... ! update all elements in the input array section SUBROUTINE UPDATE(S) INTEGER S(L4:H4:S4, L3:H3:S3) ... S(J,I) = ... ... END SUBROUTINE }}} => {{{ ... UPDATE( f_arr_sect( // Constructs a wrapper for array section A, // 1. The array identifier (int[3][2]){ // 2. Dimension information {L2+X, K}, // Lower-bound for each dim. {H2-Y, K}, // Upper-bound for each dim. {S2*Z, S1} // Idx. step for each dim } ) // This instance is freed in subroutine. ); UPDATE( f_arr_full(B) // Constructs a wrapper for full array arg ); ... void UPDATE(f_arr _S) { // Change to _S as an intermediate instance f_arr S = f_arr_sect( // A wrapper reshaped with new idx. sys. _S, // 1. the input array _S (int[3][2]){ // 2. new dimension info {L4, L3}, // New lower-bound for each dim. {H4, H3}, // New upper-bound for each dim. {S4, S3}. // New idx. step for each dim } ); ... *((int*)f_arr_subscript(S, (int[2]){J, I})) = ... ... // free the outer most wrapper (i.e. S) f_arr_destroy(S); // free the intermediate wrapper (i.e. _S), // whose construction is inlined in the calling statement. f_arr_destroy(_S); } }}} === 1.4 Fortran array reshape w/ diff. dim === In-progress. === 1.5 Fortran Array Implementation === `fortran-array.cvl` {{{ #include #include #include typedef struct CIVL_FORTRAN_ARRAY { // The number of dimensions int num_dims; // Dimention Info int *lbnds; // Left bounds for each dim. int *rbnds; // Right bounds for each dim. int *dists; // Distances of two neighbour elements in each dim. // Data Info unsigned int size_data; void* data; // Source CIVL_FORTRAN_ARRAY_TYPE struct CIVL_FORTRAN_ARRAY *src_arr; } * f_arr; /* Returns the sequential position in a row-major order */ int calc_seq_pos(f_arr arr, int shfts[]) { int n_dims = arr->num_dims; int *lbnds = arr->lbnds; int *rbnds = arr->rbnds; int *dists = arr->dists; int seq_pos = 0; int size_dim = 1; for(int i=n_dims-1; i>=0; i--) { seq_pos += (shfts[i]) * size_dim; size_dim *= (rbnds[i] - lbnds[i]) / dists[i] + 1; } return seq_pos; } int get_seq_pos(f_arr arr, int idxes[]) { /* PRE: 'arr' shall NOT be NULL. */ // EXTRACT: the cur. arr. info. int n_dims = arr->num_dims; int *lbnds = arr->lbnds; int *dists = arr->dists; int shfts[n_dims]; // CALC.: rel. shifts for each dim. in cur. arr. for (int i=0; isrc_arr; if (sec == NULL) // the cur. arr. is the original one. return calc_seq_pos(arr, shfts); //else calc. the abs. indexes in src. arr. int idxes_src[n_dims]; // EXTRACT: the source section info. lbnds = sec->lbnds; dists = sec->dists; // CALC.: abs. indexes for each dim. in the src. arr. for (int i=0; isrc_arr, idxes_src); } f_arr f_arr_create(unsigned int elem_size, int dim_num, int dim_info[3][dim_num]) { f_arr arr = (f_arr)malloc(sizeof(struct CIVL_FORTRAN_ARRAY)); int elem_total = 1; int lbnd, rbnd, dist; arr->num_dims = dim_num; arr->lbnds = (int*)malloc(dim_num * sizeof(int)); arr->rbnds = (int*)malloc(dim_num * sizeof(int)); arr->dists = (int*)malloc(dim_num * sizeof(int)); for (int i=dim_num-1; i>=0; i--) { lbnd = dim_info[0][i]; rbnd = dim_info[1][i]; dist = dim_info[2][i]; arr->lbnds[i] = lbnd; arr->rbnds[i] = rbnd; arr->dists[i] = dist; elem_total *= (dim_info[1][i] - dim_info[0][i]) / dim_info[2][i] + 1; } arr->size_data = elem_size; arr->data = malloc(elem_size * elem_total); arr->src_arr = NULL; return arr; } f_arr f_arr_sect(f_arr arr, int sec_info[3][arr->num_dims]) { f_arr sec = (f_arr)malloc(sizeof(struct CIVL_FORTRAN_ARRAY)); int dim_num = arr->num_dims; sec->num_dims = dim_num; sec->lbnds = (int*)malloc(dim_num * sizeof(int)); sec->rbnds = (int*)malloc(dim_num * sizeof(int)); sec->dists = (int*)malloc(dim_num * sizeof(int)); for (int i=dim_num-1; i>=0; i--) { sec->lbnds[i] = sec_info[0][i]; sec->rbnds[i] = sec_info[1][i]; sec->dists[i] = sec_info[2][i]; } sec->size_data = arr->size_data; sec->data = arr->data; sec->src_arr = arr; return sec; } f_arr f_arr_full(f_arr arr) { f_arr img = (f_arr)malloc(sizeof(struct CIVL_FORTRAN_ARRAY)); int dim_num = arr->num_dims; img->num_dims = dim_num; img->lbnds = (int*)malloc(dim_num * sizeof(int)); img->rbnds = (int*)malloc(dim_num * sizeof(int)); img->dists = (int*)malloc(dim_num * sizeof(int)); memcpy(img->lbnds, arr->lbnds, dim_num*sizeof(int)); memcpy(img->rbnds, arr->rbnds, dim_num*sizeof(int)); memcpy(img->dists, arr->dists, dim_num*sizeof(int)); img->size_data = arr->size_data; img->data = arr->data; img->src_arr = arr; return img; } void *f_arr_subscript(f_arr arr, int idxes[]) { int seq_pos = get_seq_pos(arr, idxes); return (arr->data) + seq_pos*arr->size_data; } void f_arr_destroy(f_arr arr){ free(arr->lbnds); free(arr->rbnds); free(arr->dists); if (arr->src_arr == NULL) free(arr->data); else arr->data = NULL; free(arr); } }}} === 1.6 A transformation example === Here is the prototype of handling Fortran array sections: {{{ /* e.g., PROGRAM EXAMPLE INTEGER SRC_ARR(1:3:1) ! source array SRC_ARR := /(1)=x,(2)=y,(3)=z/ ! source section SRC_ARR(1:3:2) := /(1)=x, (3)=z/ CALL CUT(2, SRC_ARR(1:3:2)) END SUBROUTINE CUT(N, SRC_SEC) INTEGER CUR_ARR(2:4:2) CUR_ARR = SRC_SEC ! current array CUR_ARR := /(2)=x, (4)=z/ END ! note1: the current array and its source section ! SAME shift: CUR_ARR and SRC_ARR(1:3:2) have a same ! 1st elem., which is x. ! DIFF index: The 1st elem. has an index of 2 in ! CUR_ARR, while 1 in SRC_ARR(1:3:2). ! note2: the source section and its source array ! SAME index: SRC_ARR and SRC_ARR(1:3:2) have a same ! indexing system. ! DIFF shift: their 2nd element are different. */ /****************************************************/ void arr1d_print(f_arr _IARR) { // INTEGER IARR(2:4:2) f_arr IARR = f_arr_sect(_IARR, (int[3][1]){{2}, {4}, {2}}); // DO I=2, 4, 2 // PRINT(IARR(I)) // END DO for (int i=2; i<=4; i+=2) printf("%d\n", *((int*)f_arr_subscript(IARR, (int[]){i}))); f_arr_destroy(IARR); f_arr_destroy(_IARR); } void _arr1d_print(const int n, f_arr _IARR) { // INTEGER IARR(N) f_arr IARR = f_arr_sect(_IARR, (int[3][1]){{1}, {n}, {1}}); // DO I=1, N // PRINT(IARR(I)) // END DO for (int i=1; i<=n; i+=1) { printf("%d\n", *((int*)f_arr_subscript(IARR, (int[]){i}))); } f_arr_destroy(IARR); f_arr_destroy(_IARR); } void test1 () { // INTEGER A(1:3:1); f_arr A = f_arr_create(sizeof(int), 1, (int[3][1]){{1}, {3}, {1}}); // DO I=1, 3 // A(I) = I*I; // END DO for(int i=1; i<=3; i++) { *((int*)f_arr_subscript(A, (int[]){i})) = i*i; } // ARR1D_PRINT(A(1:3:2)) arr1d_print(f_arr_sect(A, (int[3][1]){{1}, {3}, {2}})); _arr1d_print(2, f_arr_sect(A, (int[3][1]){{2}, {3}, {1}})); f_arr_destroy(A); } /************************************************/ void mat_print(const int n,const int m, f_arr _mat) { // INTEGER MAT(N, M) f_arr mat = f_arr_sect(_mat, (int[3][2]){{1,1}, {m,n}, {1,1}}); // DO I=1,M // DO J=1,N // PRINT(MAT(J,I), ", ") // END DO // PRINT("\n") // END DO for (int i=1; i<=m; i++) { for (int j=1; j<=n; j++) printf("%d%s", *((int*)f_arr_subscript(mat, (int[2]){i, j})), ", "); printf("%s", "\n"); } f_arr_destroy(mat); f_arr_destroy(_mat); } void mxm(int n1, f_arr _ia, int n2, f_arr _ib, int n3, f_arr _ic) { // INTEGER N1, N2, N3 // INTEGER IA(N2, N1), IB(N3, N2), IC(N3, N1) f_arr ia = f_arr_sect(_ia, (int[3][2]){{1,1}, {n1,n2}, {1,1}}); f_arr ib = f_arr_sect(_ib, (int[3][2]){{1,1}, {n2,n3}, {1,1}}); f_arr ic = f_arr_sect(_ic, (int[3][2]){{1,1}, {n1,n3}, {1,1}}); for (int j=1; j<=n3; j++) for (int i=1; i<=n1; i++) for (int k=1; k<=n2; k++) *(int*)f_arr_subscript(ic, (int[2]){j, i}) = *(int*)f_arr_subscript(ic, (int[2]){j, i}) + *(int*)f_arr_subscript(ia, (int[2]){k, i}) * *(int*)f_arr_subscript(ib, (int[2]){j, k}); } void test_mxm() { // INTEGER N1=2, N2=1, N3=3 int n1=2, n2=1, n3=3; // INTEGER IA(N1, N2), IB(N2, N3), IC(N1, N3) f_arr ia = f_arr_create(sizeof(int), 2, (int[3][2]){{1,1}, {n2, n1}, {1,1}}); f_arr ib = f_arr_create(sizeof(int), 2, (int[3][2]){{1,1}, {n3, n2}, {1,1}}); f_arr ic = f_arr_create(sizeof(int), 2, (int[3][2]){{1,1}, {n3, n1}, {1,1}}); // IA = 2 // IB = -2 // IC = 0 for (int j=1; j<=n2; j++) for (int i=1; i<=n1; i++) *(int*)f_arr_subscript(ia, (int[2]){j, i}) = 2; for (int j=1; j<=n3; j++) for (int i=1;i<=n2; i++) *(int*)f_arr_subscript(ib, (int[2]){j, i}) = -2; for (int j=1; j<=n3; j++) for (int i=1; i<=n1; i++) *(int*)f_arr_subscript(ic, (int[2]){j, i}) = 0; f_arr arg_ia, arg_ib, arg_ic; // MXM(N1, IA, N2, IB, N3, IC) arg_ia = f_arr_full(ia); arg_ib = f_arr_full(ib); arg_ic = f_arr_full(ic); mxm(n1, arg_ia, n2, arg_ib, n3, arg_ic); f_arr_destroy(arg_ia); f_arr_destroy(arg_ib); f_arr_destroy(arg_ic); // MAT_PRINT(N, M, IC) arg_ic = f_arr_full(ic); mat_print(n3,n1,arg_ic); f_arr_destroy(arg_ic); f_arr_destroy(ia); f_arr_destroy(ib); f_arr_destroy(ic); } void test_neg_stride() { // INTEGER A(1:21:2); f_arr A = f_arr_create( sizeof(int), 1, (int[3][1]){{1}, {21}, {2}}); // DO I=1, 21, 2 // A(I) = I / 2 + 1; // END DO for(int i=1; i<=21; i+=2) *(int*)f_arr_subscript(A, (int[]){i}) = i/2 + 1; // ARR1D_PRINT(6, A(21:1:-4)) f_arr sec_A_0 = f_arr_sect(A, (int[3][1]){{21}, {1}, {-4}}); _arr1d_print(6, sec_A_0); f_arr_destroy(sec_A_0); f_arr_destroy(A); } void test_2d_to_1d() { // INTEGER M=3, N=4, K=M*N int m=3, n=4, k=m*n; // INTEGER IA(M, N) f_arr ia = f_arr_create(sizeof(int), 2, (int[3][2]){{1,1}, {n, m}, {1,1}}); for (int j=1; j<=n; j++) for (int i=1; i<=m; i++) *(int*)f_arr_subscript(ia, (int[2]){j,i}) = (j-1)*m + i; mat_print(m,n,f_arr_full(ia)); _arr1d_print(k, f_arr_full(ia)); f_arr_destroy(ia); } int main() { //test1(); //test_mxm(); //test_neg_stride(); test_2d_to_1d(); return 0; } }}}