Files
SAPFOR/Sapfor/_src/SageAnalysisTool/OmegaForSage/cover.cpp
2025-03-12 12:37:19 +03:00

428 lines
12 KiB
C++

/* 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 <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}