fixed amb887 - 4d+ arrays were generated wrong

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401478
This commit is contained in:
David Anderson 2007-09-25 21:45:25 +00:00
parent 058e832d16
commit 2df94fb594
3 changed files with 209 additions and 51 deletions

View File

@ -39,17 +39,22 @@
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
Optimization="3"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
AdditionalIncludeDirectories="..\..\..\public\sourcepawn"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
BasicRuntimeChecks="0"
RuntimeLibrary="1"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@ -118,8 +123,8 @@
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
EnableIntrinsicFunctions="false"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
AdditionalIncludeDirectories="..\..\..\public\sourcepawn"
@ -211,10 +216,26 @@
<File
RelativePath="..\sc1.c"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\sc2.c"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\sc3.c"

View File

@ -849,4 +849,15 @@ SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */
#endif /* SC_SKIP_VDECL */
typedef struct array_info_s
{
const int *dim_list; /* Dimension sizes */
int dim_count; /* Number of dimensions */
const int *lastdim_list; /* Sizes of last dimensions, if variable */
const cell *dim_offs_precalc; /* Cached calculations into the lastdim_list array */
cell *data_offs; /* Current offset AFTER the indirection vectors (data) */
int *cur_dims; /* Current dimensions the recursion is at */
cell *base; /* &litq[startlit] */
} array_info_t;
#endif /* SC_H_INCLUDED */

View File

@ -2469,53 +2469,179 @@ static cell calc_arraysize(int dim[],int numdim,int cur)
return newsize;
}
static cell adjust_indirectiontables(int dim[],int numdim,int cur,cell increment,
static cell gen_indirection_vecs(array_info_t *ar, int dim, cell cur_offs)
{
int i;
cell write_offs = cur_offs;
cell *data_offs = ar->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<numdim);
assert(increment>=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; d<dim[cur]; d++)
litq[base++]=(dim[cur]+d*(dim[cur+1]-1)+increment) * sizeof(cell);
accum=dim[cur]*(dim[cur+1]-1);
} else {
/* final dimension is variable length */
constvalue *ld;
assert(dim[cur+1]==0);
assert(lastdim!=NULL);
assert(skipdim!=NULL);
accum=0;
/* skip the final dimension sizes for all earlier major dimensions */
for (d=0,ld=lastdim->next; d<*skipdim; d++,ld=ld->next) {
assert(ld!=NULL);
} /* for */
for (d=0; d<dim[cur]; d++) {
assert(ld!=NULL);
assert(strtol(ld->name,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+2<numdim) { /* are there at least 2 dimensions below this one? */
increment+=(dim[cur]-1)*dim[cur+1]; /* this many indirection tables follow */
for (d=0; d<dim[cur]; d++)
increment+=adjust_indirectiontables(dim,numdim,cur+1,increment,-1,lastdim,skipdim);
} /* if */
return accum;
if (numdim == 1)
{
return;
}
tbl_size = calc_indirection(dim, numdim, 0);
memset(cur_dims, 0, sizeof(cur_dims));
/**
* Flatten the last dimension array list -- this makes
* things MUCH easier in the indirection calculator.
*/
if (lastdim)
{
int i;
constvalue *ld = lastdim->next;
/* 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 */