00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00044 #include "ctrump/ast/ast.h"
00045 #include "ctrump/analyzer/deptest.h"
00046 #include "ctrump/analyzer/loop.h"
00047 #include "ctrump/common/intmap.h"
00048 #include "ctrump/common/abort.h"
00049 #include "ctrump/common/varray.h"
00050 #include <assert.h>
00051
00055 struct distance_vector {
00056 struct ctrump_loop_memory_access *store;
00057 struct ctrump_loop_memory_access *load;
00058 struct ctrump_depend_distance *vector;
00059 };
00060
00064 struct dependence_info_node {
00065 struct ctrump_loop_memory_access *first_occur;
00066 struct ctrump_varray distance_vectors;
00067 };
00068
00069
00074 struct dependence_info {
00075 struct ctrump_varray nodes;
00076 };
00077
00081 static void
00082 append_have_multiple_level(struct ctrump_varray *errors,
00083 struct ctrump_loop_memory_access *ma0,
00084 struct ctrump_loop_memory_access *ma1,
00085 struct ctrump_mempool *tmp_alloc)
00086 {
00087 struct ctrump_loop_dependence_analyze_error *e;
00088 VA_NEWELEM_P(errors, tmp_alloc);
00089 e = VA_LAST_PTR(struct ctrump_loop_dependence_analyze_error, errors);
00090
00091 e->code = CTRUMP_LOOP_DEPENDENCE_ANALYZE_HAVE_MULTIPLE_LEVEL;
00092 e->u.have_multi_level.access0 = ma0;
00093 e->u.have_multi_level.access1 = ma1;
00094 }
00095
00099 static void
00100 append_have_multiple_index(struct ctrump_varray *errors,
00101 struct ctrump_loop_memory_access *ma,
00102 struct ctrump_mempool *tmp_alloc)
00103 {
00104 struct ctrump_loop_dependence_analyze_error *e;
00105 VA_NEWELEM_P(errors, tmp_alloc);
00106 e = VA_LAST_PTR(struct ctrump_loop_dependence_analyze_error, errors);
00107
00108 e->code = CTRUMP_LOOP_DEPENDENCE_ANALYZE_HAVE_MULTIPLE_INDEX;
00109 e->u.have_miv.access = ma;
00110 }
00111
00115 static void
00116 append_have_weak_subscript(struct ctrump_varray *errors,
00117 struct ctrump_loop_subscript *sub0,
00118 struct ctrump_loop_subscript *sub1,
00119 struct ctrump_loop_memory_access *ma0,
00120 struct ctrump_loop_memory_access *ma1,
00121 struct ctrump_mempool *tmp_alloc)
00122 {
00123 struct ctrump_loop_dependence_analyze_error *e;
00124 VA_NEWELEM_P(errors, tmp_alloc);
00125 e = VA_LAST_PTR(struct ctrump_loop_dependence_analyze_error, errors);
00126
00127 e->code = CTRUMP_LOOP_DEPENDENCE_ANALYZE_HAVE_WEAK_SUBSCRIPT;
00128 e->u.have_weak.sub0 = sub0;
00129 e->u.have_weak.sub1 = sub1;
00130 e->u.have_weak.access0 = ma0;
00131 e->u.have_weak.access1 = ma1;
00132 }
00133
00137 static void
00138 append_have_complicated_subscript(struct ctrump_varray *errors,
00139 struct ctrump_loop_subscript *sub0,
00140 struct ctrump_loop_subscript *sub1,
00141 struct ctrump_loop_memory_access *ma0,
00142 struct ctrump_loop_memory_access *ma1,
00143 int sub_index,
00144 struct ctrump_mempool *tmp_alloc)
00145 {
00146 struct ctrump_loop_dependence_analyze_error *e;
00147 VA_NEWELEM_P(errors, tmp_alloc);
00148 e = VA_LAST_PTR(struct ctrump_loop_dependence_analyze_error, errors);
00149
00150 e->code = CTRUMP_LOOP_DEPENDENCE_ANALYZE_HAVE_COMPLICATED_SUBSCRIPT;
00151 e->u.have_complicated_subscript.sub0 = sub0;
00152 e->u.have_complicated_subscript.sub1 = sub1;
00153 e->u.have_complicated_subscript.access0 = ma0;
00154 e->u.have_complicated_subscript.access1 = ma1;
00155 e->u.have_complicated_subscript.sub_index = sub_index;
00156 }
00157
00158 #define LOAD 0
00159 #define STORE 1
00160
00164 static int
00165 iv_test(struct ctrump_loop_iv *iv0,
00166 struct ctrump_loop_iv *iv1)
00167 {
00168
00169
00170
00171 return (iv0->incr == iv1->incr) && (iv0->iv_level == iv1->iv_level);
00172 }
00173
00177 static int
00178 invariant_test(struct ctrump_var *var0,
00179 struct ctrump_var *var1)
00180 {
00181
00182
00183 return var0 == var1;
00184 }
00185
00189 static void
00190 strong_siv(struct ctrump_depend_distance *dest,
00191 struct ctrump_loop_subscript *x,
00192 struct ctrump_loop_subscript *y)
00193 {
00194 dest->code = CTRUMP_DEPEND_DISTANCE_STRONG_SIV;
00195 dest->u.strong_siv.index0 = y->indices[0];
00196 dest->u.strong_siv.index1 = x->indices[0];
00197 dest->u.strong_siv.distance = x->offset - y->offset;
00198 }
00199
00203 static int
00204 test_index(struct ctrump_varray *errors,
00205 struct ctrump_intmap *array_map,
00206 struct ctrump_loop_memory_access *ma,
00207 struct ctrump_mempool *tmp_alloc,
00208 int load_store)
00209 {
00210 int found;
00211 struct ctrump_intmap_bucket *b;
00212 struct ctrump_var *array_var = ma->array.var;
00213 struct dependence_info *ai;
00214 int i, n;
00215 struct ctrump_loop_subscript *cur_ss = ma->subscripts;
00216
00217 n = ma->num_subscript;
00218
00219
00220 for (i=0; i<n; i++) {
00221 if (cur_ss[i].num_index == 0) {
00222
00223 } else {
00224 if (cur_ss[i].num_index != 1) {
00225 append_have_multiple_index(errors, ma, tmp_alloc);
00226 return 0;
00227 }
00228 }
00229 }
00230
00231 if (load_store == STORE) {
00232 b = ctrump_intmap_lookup_add(array_map, &found, array_var->id);
00233 } else {
00234 b = ctrump_intmap_lookup_bucket(array_map, &found, array_var->id);
00235 }
00236 if (found) {
00237 int j;
00238 struct dependence_info *info = b->val;
00239 int num_node = info->nodes.nelem;
00240 struct dependence_info_node *nodes = info->nodes.elements;
00241 for (j=0; j<num_node; j++) {
00242 struct dependence_info_node *node = &nodes[j];
00243 struct ctrump_loop_memory_access *prev_ma = node->first_occur;
00244 struct ctrump_loop_subscript *prev_ss;
00245 struct ctrump_depend_distance *distvec = ctrump_mempool_alloc(tmp_alloc, sizeof(struct ctrump_depend_distance)*n);
00246 int cur_ns = ma->num_subscript, prev_ns = prev_ma->num_subscript;
00247 struct distance_vector dv;
00248
00249 prev_ss = prev_ma->subscripts;
00250
00251
00252 i = 0;
00253 for (i=0 ;; i++) {
00254 struct ctrump_loop_subscript *x, *y;
00255 int nl, nr;
00256 struct ctrump_loop_index *il, *ir;
00257 struct ctrump_depend_distance distance;
00258
00259 if (i >= cur_ns ||
00260 i >= prev_ns) {
00261 if (cur_ns == prev_ns) {
00262
00263 goto all_strong;
00264 } else {
00265 append_have_multiple_level(errors, prev_ma, ma, tmp_alloc);
00266 return 0;
00267 }
00268 }
00269
00270 x = &cur_ss[i];
00271 y = &prev_ss[i];
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 if (x->code == CTRUMP_LOOP_SUBSCRIPT_RECORD_MEMBER) {
00291 if (y->code == CTRUMP_LOOP_SUBSCRIPT_RECORD_MEMBER_TERMINAL) {
00292 goto always_independent;
00293 }
00294
00295 assert(y->code == CTRUMP_LOOP_SUBSCRIPT_RECORD_MEMBER);
00296
00297 if (x->u.record_member.member_name == y->u.record_member.member_name) {
00298 distance.code = CTRUMP_DEPEND_DISTANCE_MEMBER_NAME_ZIV;
00299 distance.u.member_name.member_name = x->u.record_member.member_name;
00300
00301 goto strong_index;
00302 } else {
00303
00304 goto always_independent;
00305 }
00306 } else if (x->code == CTRUMP_LOOP_SUBSCRIPT_RECORD_MEMBER_TERMINAL) {
00307 if (y->code == CTRUMP_LOOP_SUBSCRIPT_RECORD_MEMBER) {
00308 goto always_independent;
00309 }
00310
00311 assert(y->code == CTRUMP_LOOP_SUBSCRIPT_RECORD_MEMBER_TERMINAL);
00312
00313 if (x->u.record_member_terminal.member_name == y->u.record_member_terminal.member_name) {
00314 distance.code = CTRUMP_DEPEND_DISTANCE_MEMBER_NAME_ZIV;
00315 distance.u.member_name.member_name = x->u.record_member.member_name;
00316
00317 goto strong_index;
00318 } else {
00319
00320 goto always_independent;
00321 }
00322
00323 } else {
00324 #define SWAP_INDEX() do { \
00325 int nt = nl; \
00326 struct ctrump_loop_index *it = il; \
00327 il = ir; \
00328 nl = nr; \
00329 ir = it; \
00330 nr = nt; \
00331 } while (0)
00332
00333 il = x->indices;
00334 ir = y->indices;
00335
00336 nl = x->num_index;
00337 nr = y->num_index;
00338
00339 if (nr == 1) {
00340 SWAP_INDEX();
00341 }
00342
00343 if (nl == 1) {
00344
00345
00346
00347
00348 if (nr == 1) {
00349 if (il[0].code != ir[0].code) {
00350
00351
00352 append_have_complicated_subscript(errors, y, x, prev_ma, ma, i, tmp_alloc);
00353 return 0;
00354 }
00355
00356 switch (il[0].code) {
00357 case CTRUMP_LOOP_INDEX_INDUCTIVE:
00358 if (!iv_test(&il[0].u.iv, &ir[0].u.iv)) {
00359 append_have_complicated_subscript(errors, y, x, prev_ma, ma, i, tmp_alloc);
00360 return 0;
00361 }
00362
00363 strong_siv(&distance, x, y);
00364 goto strong_index;
00365
00366 case CTRUMP_LOOP_INDEX_POINTER_INC:
00367
00368 strong_siv(&distance, x, y);
00369 goto strong_index;
00370
00371 case CTRUMP_LOOP_INDEX_INVARIANT:
00372 if (!invariant_test(il[0].u.invariant, ir[0].u.invariant)) {
00373
00374
00375 append_have_complicated_subscript(errors, y, x, prev_ma, ma, i, tmp_alloc);
00376 return 0;
00377 }
00378
00379
00380 if (y->offset != x->offset) {
00381
00382 goto always_independent;
00383 }
00384
00385 distance.code = CTRUMP_DEPEND_DISTANCE_INVARIANT_ZIV;
00386 distance.u.invariant.var = il[0].u.invariant;
00387 goto strong_index;
00388 }
00389 } else {
00390 append_have_weak_subscript(errors, y, x, prev_ma, ma, tmp_alloc);
00391 return 0;
00392 }
00393 } else {
00394 if (y->offset != x->offset) {
00395 goto always_independent;
00396 }
00397
00398 distance.code = CTRUMP_DEPEND_DISTANCE_CONSTANT_ZIV;
00399 goto strong_index;
00400 }
00401 }
00402
00403 strong_index:
00404 distvec[i] = distance;
00405 }
00406
00407
00408 all_strong:
00409 dv.vector = distvec;
00410 dv.store = prev_ma;
00411 dv.load = ma;
00412 VA_PUSH_P(struct distance_vector, &node->distance_vectors, dv, tmp_alloc);
00413 return 1;
00414
00415 always_independent:
00416 continue;
00417 }
00418
00419 } else {
00420 if (load_store == STORE) {
00421 struct dependence_info_node *n;
00422 ai = ctrump_mempool_alloc(tmp_alloc, sizeof(*ai));
00423 ctrump_varray_init_pool(&ai->nodes, 4, sizeof(*n), tmp_alloc);
00424 VA_NEWELEM_P(&ai->nodes, tmp_alloc);
00425
00426 n = VA_LAST_PTR(struct dependence_info_node, &ai->nodes);
00427 ctrump_varray_init_pool(&n->distance_vectors, 4, sizeof(struct distance_vector), tmp_alloc);
00428 n->first_occur = ma;
00429 b->val = ai;
00430 }
00431 }
00432
00433 if (load_store == STORE) {
00434 struct dependence_info_node *n;
00435 ai = b->val;
00436 VA_NEWELEM_P(&ai->nodes, tmp_alloc);
00437 n = VA_LAST_PTR(struct dependence_info_node, &ai->nodes);
00438 ctrump_varray_init_pool(&n->distance_vectors, 4, sizeof(struct distance_vector), tmp_alloc);
00439 n->first_occur = ma;
00440 b->val = ai;
00441 }
00442
00443
00444 return 1;
00445 }
00446
00451 static int
00452 get_distance_vector(struct ctrump_loop_info_node *node,
00453 struct ctrump_mempool *loop_alloc)
00454 {
00455 struct ctrump_mempool tmp_alloc;
00456 struct ctrump_intmap array_map;
00457 struct ctrump_varray errors;
00458
00459 int have_error_in_inner = 0;
00460 int have_error = 0;
00461 int i, j, k, l, n = node->num_child, r;
00462
00463 for (i=0; i<n; i++) {
00464 int r = get_distance_vector(node->children[i], loop_alloc);
00465 if (! r) have_error_in_inner = 1;
00466 }
00467
00468 if (have_error_in_inner) {
00469 node->depinfo.code = CTRUMP_LOOP_DEPINFO_HAVE_ERROR_INNER;
00470 return 0;
00471 }
00472
00473 ctrump_mempool_init(&tmp_alloc, 1024);
00474 ctrump_intmap_init_pool(&array_map, 23, &tmp_alloc);
00475 ctrump_varray_init_pool(&errors, 16, sizeof(struct ctrump_loop_dependence_analyze_error), &tmp_alloc);
00476
00477 n = node->num_parallel_store;
00478 for (i=0; i<n; i++) {
00479 struct ctrump_loop_memory_access *ma = &node->parallel_stores[i];
00480 if (!test_index(&errors, &array_map, ma, &tmp_alloc, STORE)) {
00481 have_error = 1;
00482 }
00483 }
00484
00485 n = node->num_parallel_load;
00486 for (i=0; i<n; i++) {
00487 struct ctrump_loop_memory_access *ma = &node->parallel_loads[i];
00488 if (!test_index(&errors, &array_map, ma, &tmp_alloc, LOAD)) {
00489 have_error = 1;
00490 }
00491 }
00492
00493 if (have_error) {
00494 r = 0;
00495 node->depinfo.code = CTRUMP_LOOP_DEPINFO_ANALYZE_ERROR;
00496
00497 node->depinfo.u.error.num_error = errors.nelem;
00498 node->depinfo.u.error.errors = ctrump_varray_copy(&errors, loop_alloc);
00499 } else {
00500 int num_vec_set;
00501 struct ctrump_intmap_iterator it;
00502 struct ctrump_intmap_bucket *b;
00503 node->depinfo.code = CTRUMP_LOOP_DEPINFO;
00504
00505 num_vec_set = 0;
00506
00507 ctrump_intmap_iterator_begin(&it, &array_map);
00508 while (ctrump_intmap_iterator_next(&b, &it, &array_map)) {
00509 struct dependence_info *info = b->val;
00510 int m = info->nodes.nelem;
00511 struct dependence_info_node *nodes = info->nodes.elements;
00512 for (j=0; j<m; j++) {
00513 struct dependence_info_node *node = &nodes[j];
00514 if (node->distance_vectors.nelem > 0) {
00515 num_vec_set ++;
00516 }
00517 }
00518 }
00519
00520 node->depinfo.u.dep_vector.num_vec_set = num_vec_set;
00521 node->depinfo.u.dep_vector.vectors = ctrump_mempool_alloc(loop_alloc,
00522 sizeof(struct ctrump_dependence_vector_set)*num_vec_set);
00523
00524 i = 0;
00525
00526
00527 ctrump_intmap_iterator_begin(&it, &array_map);
00528 while (ctrump_intmap_iterator_next(&b, &it, &array_map)) {
00529 struct dependence_info *info = b->val;
00530 int m = info->nodes.nelem;
00531 struct dependence_info_node *nodes = info->nodes.elements;
00532 for (l=0; l<m; l++) {
00533 struct dependence_info_node *dep_node = &nodes[l];
00534 if (dep_node->distance_vectors.nelem > 0) {
00535 int num_subscript = dep_node->first_occur->num_subscript;
00536 int num_vector = dep_node->distance_vectors.nelem;
00537 struct ctrump_depend_distance *vectors = ctrump_mempool_alloc(loop_alloc,
00538 sizeof(struct ctrump_depend_distance)*num_subscript*num_vector);
00539 struct distance_vector *dv = dep_node->distance_vectors.elements;
00540 struct ctrump_loop_memory_access_pair *accesses = ctrump_mempool_alloc(loop_alloc,
00541 sizeof(*accesses)*num_vector);
00542
00543 node->depinfo.u.dep_vector.vectors[i].num_subscript = num_subscript;
00544 node->depinfo.u.dep_vector.vectors[i].num_vector = num_vector;
00545 node->depinfo.u.dep_vector.vectors[i].distance_vectors = vectors;
00546 node->depinfo.u.dep_vector.vectors[i].array_var = dep_node->first_occur->array.var;
00547 node->depinfo.u.dep_vector.vectors[i].accesses = accesses;
00548
00549 for (j=0; j<num_vector; j++) {
00550 struct ctrump_depend_distance *v = vectors + j*num_subscript;
00551 for (k=0; k<num_subscript; k++) {
00552 v[k] = dv[j].vector[k];
00553 }
00554
00555 accesses[j].store = dv[j].store;
00556 accesses[j].load = dv[j].load;
00557 }
00558
00559 i++;
00560 }
00561 }
00562 }
00563
00564 r = 1;
00565 }
00566
00567 ctrump_mempool_destroy(&tmp_alloc);
00568
00569 return r;
00570 }
00571
00572 void
00573 ctrump_get_loop_depinfo(struct ctrump_loop_info *loop,
00574 int *id,
00575 struct ctrump_mempool *loop_alloc)
00576 {
00577 if (!get_distance_vector(loop->root, loop_alloc)) {
00578
00579 return;
00580 }
00581 }