/* Extract a common guard from the grafts in "list" that can be hoisted * out of the current level. If no such guard can be found, then return * a universal set. * * If all the grafts in the list have the same guard and if this guard * is independent of the current level, then it can be hoisted out. * Otherwise, we return the unshifted simple hull of the guards. * * The special case for equal guards is needed in case those guards * are non-convex. Taking the simple hull would remove information * and would not allow for these guards to be hoisted completely. */ static __isl_give isl_set *extract_hoistable_guard( __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build) { int i, n; int depth; isl_ast_graft *graft_0; int equal; isl_set *guard; if (!list || !build) return NULL; n = isl_ast_graft_list_n_ast_graft(list); if (n == 0) return isl_set_universe(isl_ast_build_get_space(build, 1)); equal = equal_independent_guards(list, build); if (equal < 0) return NULL; graft_0 = isl_ast_graft_list_get_ast_graft(list, 0); if (!graft_0) return NULL; guard = isl_set_copy(graft_0->guard); isl_ast_graft_free(graft_0); if (equal) return guard; depth = isl_ast_build_get_depth(build); if (depth < isl_set_dim(guard, isl_dim_set)) { guard = isl_set_remove_divs_involving_dims(guard, isl_dim_set, depth, 1); guard = isl_set_eliminate(guard, isl_dim_set, depth, 1); guard = isl_set_compute_divs(guard); } for (i = 1; i < n; ++i) { isl_ast_graft *graft; isl_basic_set *hull; int is_universe; is_universe = isl_set_plain_is_universe(guard); if (is_universe < 0) guard = isl_set_free(guard); if (is_universe) break; graft = isl_ast_graft_list_get_ast_graft(list, i); if (!graft) { guard = isl_set_free(guard); break; } guard = isl_set_union(guard, isl_set_copy(graft->guard)); hull = isl_set_unshifted_simple_hull(guard); guard = isl_set_from_basic_set(hull); isl_ast_graft_free(graft); } return guard; }
/* Extract a common guard from the grafts in "list" that can be hoisted * out of the current level. If no such guard can be found, then return * a universal set. * * If all the grafts in the list have the same guard and if this guard * is independent of the current level, then it can be hoisted out. * If there is only one graft in the list and if its guard * depends on the current level, then we eliminate this level and * return the result. * * Otherwise, we return the unshifted simple hull of the guards. * In order to be able to hoist as many constraints as possible, * but at the same time avoid hoisting constraints that did not * appear in the guards in the first place, we intersect the guards * with all the information that is available (i.e., the domain * from the build and the enforced constraints of the graft) and * compute the unshifted hull of the result using only constraints * from the original guards. * In particular, intersecting the guards with other known information * allows us to hoist guards that are only explicit is some of * the grafts and implicit in the others. * * The special case for equal guards is needed in case those guards * are non-convex. Taking the simple hull would remove information * and would not allow for these guards to be hoisted completely. */ __isl_give isl_set *isl_ast_graft_list_extract_hoistable_guard( __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build) { int i, n; int equal; isl_ctx *ctx; isl_set *guard; isl_set_list *set_list; isl_basic_set *hull; if (!list || !build) return NULL; n = isl_ast_graft_list_n_ast_graft(list); if (n == 0) return isl_set_universe(isl_ast_build_get_space(build, 1)); equal = equal_independent_guards(list, build); if (equal < 0) return NULL; if (equal || n == 1) { isl_ast_graft *graft_0; graft_0 = isl_ast_graft_list_get_ast_graft(list, 0); if (!graft_0) return NULL; guard = isl_set_copy(graft_0->guard); if (!equal) guard = hoist_guard(guard, build); isl_ast_graft_free(graft_0); return guard; } ctx = isl_ast_build_get_ctx(build); set_list = isl_set_list_alloc(ctx, n); guard = isl_set_empty(isl_ast_build_get_space(build, 1)); for (i = 0; i < n; ++i) { isl_ast_graft *graft; isl_basic_set *enforced; isl_set *guard_i; graft = isl_ast_graft_list_get_ast_graft(list, i); enforced = isl_ast_graft_get_enforced(graft); guard_i = isl_set_copy(graft->guard); isl_ast_graft_free(graft); set_list = isl_set_list_add(set_list, isl_set_copy(guard_i)); guard_i = isl_set_intersect(guard_i, isl_set_from_basic_set(enforced)); guard_i = isl_set_intersect(guard_i, isl_ast_build_get_domain(build)); guard = isl_set_union(guard, guard_i); } hull = isl_set_unshifted_simple_hull_from_set_list(guard, set_list); guard = isl_set_from_basic_set(hull); return hoist_guard(guard, build); }
CloogInput *Cloog::buildCloogInput() { CloogDomain *Context = cloog_domain_from_isl_set(isl_set_copy(S->getContext())); CloogUnionDomain *Statements = buildCloogUnionDomain(); CloogInput *Input = cloog_input_alloc (Context, Statements); return Input; }
/* Compute the size of a bounding box around the origin and "set", * where "set" is assumed to contain only non-negative elements. * In particular, compute the maximal value of "set" in each direction * and add one. */ __isl_give isl_multi_pw_aff *ppcg_size_from_extent(__isl_take isl_set *set) { int i, n; isl_multi_pw_aff *mpa; n = isl_set_dim(set, isl_dim_set); mpa = isl_multi_pw_aff_zero(isl_set_get_space(set)); for (i = 0; i < n; ++i) { isl_space *space; isl_aff *one; isl_pw_aff *bound; if (!isl_set_dim_has_upper_bound(set, isl_dim_set, i)) { const char *name; name = isl_set_get_tuple_name(set); if (!name) name = ""; fprintf(stderr, "unable to determine extent of '%s' " "in dimension %d\n", name, i); set = isl_set_free(set); } bound = isl_set_dim_max(isl_set_copy(set), i); space = isl_pw_aff_get_domain_space(bound); one = isl_aff_zero_on_domain(isl_local_space_from_space(space)); one = isl_aff_add_constant_si(one, 1); bound = isl_pw_aff_add(bound, isl_pw_aff_from_aff(one)); mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, bound); } isl_set_free(set); return mpa; }
/* Check if the constraints in "set" imply any stride on set dimension "pos" and * store the results in data->stride and data->offset. * * In particular, compute the affine hull and then check if * any of the constraints in the hull impose any stride on the dimension. * If no such constraint can be found, then the offset is taken * to be the zero expression and the stride is taken to be one. */ static void set_detect_stride(__isl_keep isl_set *set, int pos, struct isl_detect_stride_data *data) { isl_basic_set *hull; hull = isl_set_affine_hull(isl_set_copy(set)); data->pos = pos; data->found = 0; data->stride = NULL; data->offset = NULL; if (isl_basic_set_foreach_constraint(hull, &detect_stride, data) < 0) goto error; if (!data->found) { data->stride = isl_val_one(isl_set_get_ctx(set)); if (data->want_offset) { isl_space *space; isl_local_space *ls; space = isl_set_get_space(set); ls = isl_local_space_from_space(space); data->offset = isl_aff_zero_on_domain(ls); } } isl_basic_set_free(hull); return; error: isl_basic_set_free(hull); data->stride = isl_val_free(data->stride); data->offset = isl_aff_free(data->offset); }
int isl_set_count_upto(__isl_keep isl_set *set, isl_int max, isl_int *count) { struct isl_counter cnt = { { &increment_counter } }; if (!set) return -1; isl_int_init(cnt.count); isl_int_init(cnt.max); isl_int_set_si(cnt.count, 0); isl_int_set(cnt.max, max); if (isl_set_scan(isl_set_copy(set), &cnt.callback) < 0 && isl_int_lt(cnt.count, cnt.max)) goto error; isl_int_set(*count, cnt.count); isl_int_clear(cnt.max); isl_int_clear(cnt.count); return 0; error: isl_int_clear(cnt.count); return -1; }
int isl_set_foreach_point(__isl_keep isl_set *set, int (*fn)(__isl_take isl_point *pnt, void *user), void *user) { struct isl_foreach_point fp = { { &foreach_point }, fn, user }; int i; if (!set) return -1; fp.dim = isl_set_get_dim(set); if (!fp.dim) return -1; set = isl_set_copy(set); set = isl_set_cow(set); set = isl_set_make_disjoint(set); set = isl_set_compute_divs(set); if (!set) goto error; for (i = 0; i < set->n; ++i) if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]), &fp.callback) < 0) goto error; isl_set_free(set); isl_dim_free(fp.dim); return 0; error: isl_set_free(set); isl_dim_free(fp.dim); return -1; }
/* Insert an if node around graft->node testing the condition encoded * in graft->guard, assuming graft->guard involves any conditions. */ static __isl_give isl_ast_graft *insert_pending_guard_node( __isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build) { if (!graft) return NULL; return insert_if_node(graft, isl_set_copy(graft->guard), build); }
/* Given an index expression "test_index" for the if condition, * an index expression "skip_index" for the skip condition and * scops for the then and else branches, construct a scop for * computing "skip_index" within the context "pc". * * The computed scop contains a single statement that essentially does * * skip_index = test_cond ? skip_cond_then : skip_cond_else * * If the skip conditions of the then and/or else branch are not affine, * then they need to be filtered by test_index. * If they are missing, then this means the skip condition is false. * * Since we are constructing a skip condition for the if statement, * the skip conditions on the then and else branches are removed. */ static struct pet_scop *extract_skip_if(__isl_take isl_multi_pw_aff *test_index, __isl_take isl_multi_pw_aff *skip_index, struct pet_scop *scop_then, struct pet_scop *scop_else, int have_else, enum pet_skip type, __isl_keep pet_context *pc, struct pet_state *state) { pet_expr *expr_then, *expr_else, *expr, *expr_skip; pet_tree *tree; struct pet_stmt *stmt; struct pet_scop *scop; isl_ctx *ctx; isl_set *domain; if (!scop_then) goto error; if (have_else && !scop_else) goto error; ctx = isl_multi_pw_aff_get_ctx(test_index); if (pet_scop_has_skip(scop_then, type)) { expr_then = pet_scop_get_skip_expr(scop_then, type); pet_scop_reset_skip(scop_then, type); if (!pet_expr_is_affine(expr_then)) expr_then = pet_expr_filter(expr_then, isl_multi_pw_aff_copy(test_index), 1); } else expr_then = universally_false(pet_context_get_space(pc)); if (have_else && pet_scop_has_skip(scop_else, type)) { expr_else = pet_scop_get_skip_expr(scop_else, type); pet_scop_reset_skip(scop_else, type); if (!pet_expr_is_affine(expr_else)) expr_else = pet_expr_filter(expr_else, isl_multi_pw_aff_copy(test_index), 0); } else expr_else = universally_false(pet_context_get_space(pc)); expr = pet_expr_from_index(test_index); expr = pet_expr_new_ternary(expr, expr_then, expr_else); expr_skip = pet_expr_from_index(isl_multi_pw_aff_copy(skip_index)); expr_skip = pet_expr_access_set_write(expr_skip, 1); expr_skip = pet_expr_access_set_read(expr_skip, 0); expr = pet_expr_new_binary(1, pet_op_assign, expr_skip, expr); domain = pet_context_get_domain(pc); tree = pet_tree_new_expr(expr); stmt = pet_stmt_from_pet_tree(isl_set_copy(domain), state->n_stmt++, tree); scop = pet_scop_from_pet_stmt(pet_context_get_space(pc), stmt); scop = pet_scop_add_boolean_array(scop, domain, skip_index, state->int_size); return scop; error: isl_multi_pw_aff_free(test_index); isl_multi_pw_aff_free(skip_index); return NULL; }
/* Construct a scop for computing the skip condition of the given type and * with index expression "skip_index" for a sequence of two scops "scop1" * and "scop2". Do so within the context "pc". * * The computed scop contains a single statement that essentially does * * skip_index = skip_cond_1 ? 1 : skip_cond_2 * * or, in other words, skip_cond1 || skip_cond2. * In this expression, skip_cond_2 is filtered to reflect that it is * only evaluated when skip_cond_1 is false. * * The skip condition on scop1 is not removed because it still needs * to be applied to scop2 when these two scops are combined. */ static struct pet_scop *extract_skip_seq( __isl_take isl_multi_pw_aff *skip_index, struct pet_scop *scop1, struct pet_scop *scop2, enum pet_skip type, __isl_keep pet_context *pc, struct pet_state *state) { pet_expr *expr1, *expr2, *expr, *expr_skip; pet_tree *tree; struct pet_stmt *stmt; struct pet_scop *scop; isl_ctx *ctx; isl_set *domain; if (!scop1 || !scop2) goto error; ctx = isl_multi_pw_aff_get_ctx(skip_index); expr1 = pet_scop_get_skip_expr(scop1, type); expr2 = pet_scop_get_skip_expr(scop2, type); pet_scop_reset_skip(scop2, type); expr2 = pet_expr_filter(expr2, pet_expr_access_get_index(expr1), 0); expr = universally_true(pet_context_get_space(pc)); expr = pet_expr_new_ternary(expr1, expr, expr2); expr_skip = pet_expr_from_index(isl_multi_pw_aff_copy(skip_index)); expr_skip = pet_expr_access_set_write(expr_skip, 1); expr_skip = pet_expr_access_set_read(expr_skip, 0); expr = pet_expr_new_binary(1, pet_op_assign, expr_skip, expr); domain = pet_context_get_domain(pc); tree = pet_tree_new_expr(expr); stmt = pet_stmt_from_pet_tree(isl_set_copy(domain), state->n_stmt++, tree); scop = pet_scop_from_pet_stmt(pet_context_get_space(pc), stmt); scop = pet_scop_add_boolean_array(scop, domain, skip_index, state->int_size); return scop; error: isl_multi_pw_aff_free(skip_index); return NULL; }
CloogUnionDomain *Cloog::buildCloogUnionDomain() { CloogUnionDomain *DU = cloog_union_domain_alloc(S->getNumParams()); for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) { ScopStmt *Stmt = *SI; if (Stmt->isFinalRead()) continue; CloogScattering *Scattering= cloog_scattering_from_isl_map(isl_map_copy(Stmt->getScattering())); CloogDomain *Domain = cloog_domain_from_isl_set(isl_set_copy(Stmt->getDomain())); std::string entryName = Stmt->getBaseName(); char *Name = (char*)malloc(sizeof(char) * (entryName.size() + 1)); strcpy(Name, entryName.c_str()); DU = cloog_union_domain_add_domain(DU, Name, Domain, Scattering, Stmt); } return DU; }
static void *isl_obj_set_copy(void *v) { return isl_set_copy((struct isl_set *)v); }
/** * Converts a SCoP as extracted by PolyOpt's auto-scop detection * into ISL representation. * * bugs/limitations: * (a) not robust to union of iteration domains in scoplib * (b) code is leaking, need proper copy constructor that duplicates all * ISL structures. */ int PolyOptISLRepresentation::convertScoplibToISL (scoplib_scop_p scop) { int i; isl_union_map* all_reads = NULL; isl_union_map* all_writes = NULL; isl_union_map* all_scheds = NULL; isl_ctx* ctxt = isl_ctx_alloc(); // 1. Prepare the arrays of unique names for statements and arrays. char buffer[32]; int nb_statements; scoplib_statement_p s; for (nb_statements = 0, s = scop->statement; s; s = s->next, nb_statements++) ; char* stmt_names[nb_statements]; for (i = 0; i < nb_statements; ++i) { sprintf (buffer, "S_%d", i); stmt_names[i] = strdup (buffer); } char* array_names[scop->nb_arrays]; for (i = 0; i < scop->nb_arrays; ++i) array_names[i] = strdup (((SgVariableSymbol*)(scop->arrays[i]))->get_name().str()); isl_union_map* umap; int stmt_id; for (s = scop->statement, stmt_id = 0; s; s = s->next, ++stmt_id) { isl_union_map* all_reads_stmt = NULL; isl_union_map* all_writes_stmt = NULL; isl_space* sp = NULL; for (i = 0; i < scop->nb_arrays; ++i) { sp = build_isl_space (scop, s, i+1, ctxt); // 1. Handle access matrices. scoplib_matrix_p m; int k; for (k = 0, m = s->read, umap = all_reads_stmt; k < 2; k++, m = s->write, umap = all_writes_stmt) { isl_map* acc_map = NULL; int row_pos = 0; do { acc_map = build_access_function (scop, s, m, sp, ctxt, &row_pos, i+1); if (acc_map) { acc_map = isl_map_set_tuple_name (acc_map, isl_dim_in, stmt_names[stmt_id]); acc_map = isl_map_set_tuple_name (acc_map, isl_dim_out, array_names[i]); if (umap == NULL) umap = isl_union_map_from_map (isl_map_copy (acc_map)); else umap = isl_union_map_union (umap, isl_union_map_from_map (isl_map_copy (acc_map))); isl_map_free (acc_map); } } while (acc_map != NULL); if (k == 0) all_reads_stmt = umap; else all_writes_stmt = umap; } } // Store the union of access functions of statement i. stmt_accfunc_read.push_back (all_reads_stmt); stmt_accfunc_write.push_back (all_writes_stmt); // 2. Handle iteration domains. isl_set* dom = build_iteration_domain (scop, s, sp, ctxt); dom = isl_set_set_tuple_name (dom, stmt_names[stmt_id]); if (all_reads_stmt != NULL) all_reads_stmt = isl_union_map_intersect_domain (isl_union_map_copy (all_reads_stmt), isl_union_set_from_set (isl_set_copy (dom))); if (all_writes_stmt != NULL) all_writes_stmt = isl_union_map_intersect_domain (all_writes_stmt, isl_union_set_from_set (isl_set_copy (dom))); // Store the iteration domain of statement i. stmt_iterdom.push_back (dom); // Store the union of access functions of statement i after intersection by domain. stmt_read_domain.push_back (all_reads_stmt); stmt_write_domain.push_back (all_writes_stmt); // Unionize the result. if (all_reads == NULL) all_reads = isl_union_map_copy (all_reads_stmt); else all_reads = isl_union_map_union (all_reads, isl_union_map_copy (all_reads_stmt)); if (all_writes == NULL) all_writes = isl_union_map_copy (all_writes_stmt); else all_writes = isl_union_map_union (all_writes, isl_union_map_copy (all_writes_stmt)); // isl_union_map_free (all_reads_stmt); // isl_union_map_free (all_writes_stmt); // 3. Handle schedules. isl_map* sched = build_schedule (scop, s, sp, ctxt); sched = isl_map_set_tuple_name (sched, isl_dim_in, stmt_names[stmt_id]); if (all_scheds == NULL) all_scheds = isl_union_map_from_map (isl_map_copy (sched)); else all_scheds = isl_union_map_union (all_scheds, isl_union_map_from_map (isl_map_copy (sched))); // Store the schedule of statement i. stmt_schedule.push_back (sched); // 4. Finalize info about the statement. stmt_body.push_back (((SgNode*)(s->body))->unparseToCompleteString()); stmt_body_ir.push_back ((SgNode*)(s->body)); } // // Debug. // isl_printer* pr = isl_printer_to_file (ctxt, stdout); // std::cout << "UNION MAP READS" << std::endl; // isl_printer_print_union_map(pr, all_reads); // printf ("\n"); // std::cout << "UNION MAP WRITES" << std::endl; // isl_printer_print_union_map(pr, all_writes); // printf ("\n"); // std::cout << "UNION MAP SCHEDULES" << std::endl; // isl_printer_print_union_map(pr, all_scheds); // printf ("\n"); for (std::vector<std::string>::iterator i = stmt_body.begin(); i != stmt_body.end(); ++i) std::cout << "stmt body: " << *i << std::endl; // Finalize SCoP representation. scop_nb_arrays = scop->nb_arrays; scop_nb_statements = stmt_schedule.size(); scop_reads = all_reads; scop_writes = all_writes; scop_scheds = all_scheds; return EXIT_SUCCESS; }