/* cover.c,v 1.1 1993/09/17 22:13:48 fbodin Exp */ /* coverage and termination tests Naming convention: Many of these functions and structures refer to "read iteration" or "write iteration" as if a test were being performed on flow dependence(s), even when the test works for other forms of dependence. */ #include #include #include #include #include "include/portable.h" #include "include/debug.h" #include "include/ip.h" #include "include/lang-interf.h" #include "include/ddomega-build.h" #include "include/ddomega-use.h" #include "include/kill.h" #include "include/cover.h" /* #include "timeTrials.h" */ possible_reasons why_no_cover_or_terminator; /* test to see if a dependence covers its destination. */ int test_for_coverage(a_access write_acc, a_access read_acc, uint write_nest, uint read_nest, uint common_nest, dir_and_dist_info *dd, char *dd_as_string) { var_id sc_vars[maxVars], r_vars[maxVars], rs_vars[maxVars]; var_id w_vars[maxVars], ws_vars[maxVars]; int Nrs, Nws, Nsc, leading_0s; read_prob_desc rpd; /* write1s = A[i] write2s unused in coverage test reads = B[j] */ Problem reads; int j, red_complete, cover; #if ! defined NDEBUG int eqs, geqs; #endif if (access_update_p(write_acc)) { set_reason(didnt_test); return(0); } assert(write_acc == Entry || access_store_p(write_acc)); #if defined newTimeTrials if (storeResult) coverTests++; #endif /* If this test is changed or removed, change ddomega-use.c to reflect that we could have non-coverage due to some reason other than "didnt_test" if we haven't got all 0's */ for (j = 1; j <= common_nest; j++) { if (!dddirtest(dd->direction, ddeq, j)) { if (omegaPrintResult) { fprintf(debug2, "coverage unlikely, not bothering to test:\n"); fprintf(debug2, " %s\n", dd_as_string); } set_reason(didnt_test); return 0; } } leading_0s = leading_zeros(dd->direction, dd->nest); /* PART 1: find sets of variables to be used in problem */ Nrs = Nws = Nsc = 0; load_bounds_and_count_steps(read_acc, r_vars, rs_vars, &Nrs); load_bounds_and_count_steps(write_acc, w_vars, ws_vars, &Nws); load_constants_for_bounds(read_acc, sc_vars, &Nsc); load_constants_for_bounds(write_acc, sc_vars, &Nsc); load_constants_for_subscripts(read_acc, sc_vars, &Nsc); load_constants_for_subscripts(write_acc, sc_vars, &Nsc); /* PART 2: assign columns to variables Protect variables representing symbolic constants and read iteration values of loop indices, because we wish to test if S implies T for all values of them.*/ read_init(&rpd, &reads, sc_and_r, Nsc, sc_vars, read_nest, r_vars, Nrs, rs_vars, write_nest, w_vars, Nws, ws_vars, 0, NIL, 0, NIL); /* PART 3: build problem */ #if !defined NDEBUG read_inv(&rpd, &reads); assert(reads.getNumEqs() == 0); assert(reads.getNumGEqs() == 0); eqs = geqs = 0; #endif /* TRY TO SET UP RED "T" PROBLEM: "i in [A] ^ A(i) << B(j) ^ A(i) sub= B(j)" If we can't completely describe the red problem, we can't test for cover - set red_complete to 0 to indicate this. */ /* i in [A] */ red_complete = bound_inner_indices_and_conditionals(&reads, &rpd.write1s, &rpd.w1steps, &rpd.nonloops, leading_0s, read_acc, red, write_acc); if (!red_complete) { if (omegaPrintResult) { fprintf(debug2, "not checking for COVER - incomplete red bounds\n"); fprintf(debug2, "of %s\n", dd_as_string); } read_cleanup(&rpd); set_reason(non_affine_red_bound); return 0; } #if ! defined NDEBUG read_inv(&rpd, &reads); #endif /* A(i) sub= B(j) */ /* equate_sub won't be 0, or there would not be a dependence */ red_complete = equate_subscripts(&reads, &rpd.reads, &rpd.write1s, &rpd.nonloops, red, read_acc, write_acc) == complete; #if ! defined NDEBUG read_inv(&rpd, &reads); #endif if (!red_complete) { if (omegaPrintResult) { fprintf(debug2, "not checking for COVER - incomplete red subscripts\n"); fprintf(debug2, "of %s\n", dd_as_string); } read_cleanup(&rpd); set_reason(non_affine_red_sub); return 0; } /* A(i) << B(j) */ constrain_with_dd(&reads, &rpd.reads, &rpd.write1s, dd, red); #if !defined NDEBUG read_inv(&rpd, &reads); for (; eqs < reads.getNumEqs(); eqs++) { assert(reads._EQs[eqs].color == red); } for (; geqs < reads.getNumGEqs(); geqs++) { assert(reads._GEQs[geqs].color == red); } #endif /* SET UP BLACK "S" PROBLEM: "j in [B]" */ bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps, &rpd.nonloops, black, read_acc); #if ! defined NDEBUG read_inv(&rpd, &reads); for (; eqs < reads.getNumEqs(); eqs++) { assert(reads._EQs[eqs].color == black); } for (; geqs < reads.getNumGEqs(); geqs++) { assert(reads._GEQs[geqs].color == black); } #endif /* PART 4: clean up */ #if ! defined NDEBUG read_inv(&rpd, &reads); #endif read_cleanup(&rpd); /* PART 5: CHECK FOR COVERAGE: Forall j, Sym, does S imply T? */ /* there must be a solution to the black equations, since they represent only j in [B] - if this were not true, there would be no flow dependencies at all */ if (omegaPrintResult) { fprintf(debug2, "starting check for COVER\n"); fprintf(debug2, "of %s\n", dd_as_string); printProblem(&reads); } cover = !hasRedEquations(&reads, 0); if (omegaPrintResult) { if (cover) fprintf(debug2, "verified COVER:\n"); else fprintf(debug2, "no COVER:\n"); printProblem(&reads); } #if defined newTimeTrials if (storeResult) { realCoverTests++; if (cover) realCovers++; } #endif set_reason((possible_reasons)cover); return cover; } /* test to see if dependence terminates its source (ie an anti-dep from a read to a write termitates the read) */ int test_for_termination(a_access read_acc, a_access write_acc, uint read_nest, uint write_nest, uint common_nest, dir_and_dist_info *dd, char *dd_as_string) { var_id sc_vars[maxVars], r_vars[maxVars], rs_vars[maxVars]; var_id w_vars[maxVars], ws_vars[maxVars]; int Nrs, Nws, Nsc, leading_0s; read_prob_desc rpd; Problem reads; int j, red_complete, termination; #if ! defined NDEBUG int eqs, geqs; #endif if (access_update_p(write_acc)) { set_reason(didnt_test); return(0); } assert(write_acc == Entry || access_store_p(write_acc)); #if defined newTimeTrials if (storeResult) terminationTests++; #endif /* If this test is changed or removed, change ddomega-use.c to reflect that we could have non-termination due to some reason other than "didnt_test" if we haven't got all 0's */ for (j = 1; j <= common_nest; j++) { if (!dddirtest(dd->direction, ddeq, j)) { if (omegaPrintResult) { fprintf(debug2, "termination unlikely, not bothering to test:\n"); fprintf(debug2, " %s\n", dd_as_string); } set_reason(didnt_test); return 0; } } leading_0s = leading_zeros(dd->direction, dd->nest); /* PART 1: find sets of variables to be used in problem */ Nrs = Nws = Nsc = 0; load_bounds_and_count_steps(read_acc, r_vars, rs_vars, &Nrs); load_bounds_and_count_steps(write_acc, w_vars, ws_vars, &Nws); load_constants_for_bounds(read_acc, sc_vars, &Nsc); load_constants_for_bounds(write_acc, sc_vars, &Nsc); load_constants_for_subscripts(read_acc, sc_vars, &Nsc); load_constants_for_subscripts(write_acc, sc_vars, &Nsc); /* PART 2: assign columns to variables Protect variables representing symbolic constants and read iteration values of loop indices, because we wish to test if S implies T for all values of them.*/ read_init(&rpd, &reads, sc_and_r, Nsc, sc_vars, read_nest, r_vars, Nrs, rs_vars, write_nest, w_vars, Nws, ws_vars, 0, NIL, 0, NIL); /* PART 3: build problem */ #if !defined NDEBUG read_inv(&rpd, &reads); assert(reads.getNumEqs() == 0); assert(reads.getNumGEqs() == 0); eqs = geqs = 0; #endif /* TRY TO SET UP RED "T" PROBLEM: "j in [B] ^ A(i) << B(j) ^ A(i) sub= B(j)" If we can't completely describe the red problem, we can't test for termination - set red_complete to 0 to indicate this. */ /* j in [B] */ red_complete = bound_inner_indices_and_conditionals(&reads, &rpd.write1s, &rpd.w1steps, &rpd.nonloops, leading_0s, read_acc, red, write_acc); if (!red_complete) { if (omegaPrintResult) { fprintf(debug2, "not checking for TERMINATION - incomplete red bounds\n"); fprintf(debug2, "of %s\n", dd_as_string); } read_cleanup(&rpd); set_reason(non_affine_red_bound); return 0; } #if ! defined NDEBUG read_inv(&rpd, &reads); #endif /* A(i) sub= B(j) */ /* equate_sub won't be 0, or there would not be a dependence */ red_complete = equate_subscripts(&reads, &rpd.reads, &rpd.write1s, &rpd.nonloops, red, read_acc, write_acc) == complete; if (!red_complete) { if (omegaPrintResult) { fprintf(debug2, "not checking for TERMINATION - incomplete red subscript\n"); fprintf(debug2, "of %s\n", dd_as_string); } read_cleanup(&rpd); set_reason(non_affine_red_sub); return 0; } #if ! defined NDEBUG read_inv(&rpd, &reads); #endif /* A(i) << B(j) */ constrain_with_dd(&reads, &rpd.write1s, &rpd.reads, dd, red); #if !defined NDEBUG read_inv(&rpd, &reads); for (; eqs < reads.getNumEqs(); eqs++) { assert(reads._EQs[eqs].color == red); } for (; geqs < reads.getNumGEqs(); geqs++) { assert(reads._GEQs[geqs].color == red); } #endif /* SET UP BLACK "S" PROBLEM: "i in [A]" */ bound_indices_and_conditionals(&reads, &rpd.reads, &rpd.rsteps, &rpd.nonloops, black, read_acc); #if ! defined NDEBUG read_inv(&rpd, &reads); for (; eqs < reads.getNumEqs(); eqs++) { assert(reads._EQs[eqs].color == black); } for (; geqs < reads.getNumGEqs(); geqs++) { assert(reads._GEQs[geqs].color == black); } #endif /* PART 4: clean up */ #if ! defined NDEBUG read_inv(&rpd, &reads); #endif read_cleanup(&rpd); /* PART 5: CHECK FOR TERMINATION: Forall i, Sym, does S imply T? */ /* there must be a solution to the black equations, since they represent only i in [A] - if this were not true, there would be no flow dependencies at all */ if (omegaPrintResult) { fprintf(debug2, "starting check for TERMINATION\n"); fprintf(debug2, "of %s\n", dd_as_string); printProblem(&reads); } termination = !hasRedEquations(&reads, 0); if (omegaPrintResult) { if (termination) fprintf(debug2, "verified TERMINATION.\n"); else fprintf(debug2, "no TERMINATION.\n"); } #if defined newTimeTrials if (storeResult) { realTerminationTests++; if (termination) realTerminators++; } #endif set_reason((possible_reasons)termination); return termination; }