From 2df94fb594f7fadf8d9569a91589dc888f294387 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 25 Sep 2007 21:45:25 +0000 Subject: [PATCH] fixed amb887 - 4d+ arrays were generated wrong --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401478 --- sourcepawn/compiler/msvc8/spcomp.vcproj | 31 +++- sourcepawn/compiler/sc.h | 11 ++ sourcepawn/compiler/sc1.c | 218 +++++++++++++++++++----- 3 files changed, 209 insertions(+), 51 deletions(-) diff --git a/sourcepawn/compiler/msvc8/spcomp.vcproj b/sourcepawn/compiler/msvc8/spcomp.vcproj index a1337101..312f8f91 100644 --- a/sourcepawn/compiler/msvc8/spcomp.vcproj +++ b/sourcepawn/compiler/msvc8/spcomp.vcproj @@ -39,17 +39,22 @@ /> + + + + + + data_offs; + + cur_offs += ar->dim_list[dim]; + + /** + * Dimension n-x where x > 2 will have sub-vectors. + * Otherwise, we just need to reference the data section. + */ + if (ar->dim_count > 2 && dim < ar->dim_count - 2) + { + /** + * For each index at this dimension, write offstes to our sub-vectors. + * After we write one sub-vector, we generate its sub-vectors recursively. + * At the end, we're given the next offset we can use. + */ + for (i = 0; i < ar->dim_list[dim]; i++) + { + ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell); + write_offs++; + ar->cur_dims[dim] = i; + cur_offs = gen_indirection_vecs(ar, dim + 1, cur_offs); + } + } else if (ar->dim_count > 1) { + /** + * In this section, there are no sub-vectors, we need to write offsets + * to the data. This is separate so the data stays in one big chunk. + * The data offset will increment by the size of the last dimension, + * because that is where the data is finally computed as. But the last + * dimension can be of variable size, so we have to detect that. + */ + if (ar->dim_list[dim + 1] == 0) + { + int vec_start = 0; + + /** + * Using the precalculated offsets, compute an index into the last + * dimension array. + */ + for (i = 0; i < dim; i++) + { + vec_start += ar->cur_dims[i] * ar->dim_offs_precalc[i]; + } + + /** + * Now, vec_start points to a vector of last dimension offsets for + * the preceding dimension combination(s). + * I.e. (1,2,i,j) in [3][4][5][] will be: + * j = 1*(4*5) + 2*(5) + i, and the parenthetical expressions are + * precalculated for us so we can easily generalize here. + */ + for (i = 0; i < ar->dim_list[dim]; i++) + { + ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell); + write_offs++; + *data_offs = *data_offs + ar->lastdim_list[vec_start + i]; + } + } else { + /** + * The last dimension size is constant. There's no extra work to + * compute the last dimension size. + */ + for (i = 0; i < ar->dim_list[dim]; i++) + { + ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell); + write_offs++; + *data_offs = *data_offs + ar->dim_list[dim + 1]; + } + } + } + + return cur_offs; +} + +static cell calc_indirection(const int dim_list[], int dim_count, int dim) +{ + cell size = dim_list[dim]; + + if (dim < dim_count - 2) + { + size += dim_list[dim] * calc_indirection(dim_list, dim_count, dim + 1); + } + + return size; +} + +static void adjust_indirectiontables(int dim[],int numdim,int cur,cell increment, int startlit,constvalue *lastdim,int *skipdim) { -static int base; - int d; - cell accum; + /* Find how many cells the indirection table will be */ + cell tbl_size; + int *dyn_list = NULL; + int cur_dims[sDIMEN_MAX]; + cell dim_offset_precalc[sDIMEN_MAX]; + array_info_t ar; - assert(cur>=0 && cur=0); - assert(cur>0 && startlit==-1 || startlit>=0 && startlit<=litidx); - if (cur==0) - base=startlit; - if (cur==numdim-1) - return 0; - /* 2 or more dimensions left, fill in an indirection vector */ - assert(dim[cur]>0); - if (dim[cur+1]>0) { - for (d=0; dnext; d<*skipdim; d++,ld=ld->next) { - assert(ld!=NULL); - } /* for */ - for (d=0; dname,NULL,16)==d); - litq[base++]=(dim[cur]+accum+increment) * sizeof(cell); - accum+=ld->value-1; - *skipdim+=1; - ld=ld->next; - } /* for */ - } /* if */ - /* create the indirection tables for the lower level */ - if (cur+2next; + + /* Get the total number of last dimensions. */ + for (i = 0; ld != NULL; i++, ld = ld->next) + { + /* Nothing */ + } + /* Store them in an array instead of a linked list. */ + dyn_list = (int *)malloc(sizeof(int) * i); + for (i = 0, ld = lastdim->next; + ld != NULL; + i++, ld = ld->next) + { + dyn_list[i] = ld->value; + } + + /** + * Pre-calculate all of the offsets. This speeds up and simplifies + * the indirection process. For example, if we have an array like: + * [a][b][c][d][], and given (A,B,C), we want to find the size of + * the last dimension [A][B][C][i], we must do: + * + * list[A*(b*c*d) + B*(c*d) + C*(d) + i] + * + * Generalizing this algorithm in the indirection process is expensive, + * so we lessen the need for nested loops by pre-computing the parts: + * (b*c*d), (c*d), and (d). + * + * In other words, finding the offset to dimension N at index I is + * I * (S[N+1] * S[N+2] ... S[N+n-1]) where S[] is the size of dimension + * function, and n is the index of the last dimension. + */ + for (i = 0; i < numdim - 1; i++) + { + int j; + + dim_offset_precalc[i] = 1; + for (j = i + 1; j < numdim - 1; j++) + { + dim_offset_precalc[i] *= dim[j]; + } + } + + ar.dim_offs_precalc = dim_offset_precalc; + ar.lastdim_list = dyn_list; + } else { + ar.dim_offs_precalc = NULL; + ar.lastdim_list = NULL; + } + + ar.base = &litq[startlit]; + ar.data_offs = &tbl_size; + ar.dim_list = dim; + ar.dim_count = numdim; + ar.cur_dims = cur_dims; + + gen_indirection_vecs(&ar, 0, 0); + + free(dyn_list); } /* initials @@ -5566,10 +5692,10 @@ static void compound(int stmt_sameline,int starttok) if (lastst!=tRETURN) destructsymbols(&loctab,nestlevel); if (lastst!=tRETURN && lastst!=tGOTO) { - popheaplist(1); + popheaplist(); popstacklist(1); } else { - popheaplist(0); + popheaplist(); popstacklist(0); } testsymbols(&loctab,nestlevel,FALSE,TRUE); /* look for unused block locals */