1 1.1 mrg /* 2 1.1 mrg * Copyright 2010 INRIA Saclay 3 1.1 mrg * Copyright 2013 Ecole Normale Superieure 4 1.1 mrg * 5 1.1 mrg * Use of this software is governed by the MIT license 6 1.1 mrg * 7 1.1 mrg * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, 8 1.1 mrg * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, 9 1.1 mrg * 91893 Orsay, France 10 1.1 mrg * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France 11 1.1 mrg */ 12 1.1 mrg 13 1.1 mrg #include <isl/hash.h> 14 1.1 mrg #include <isl_union_macro.h> 15 1.1 mrg 16 1.1 mrg /* A union of expressions defined over different domain spaces. 17 1.1 mrg * "space" describes the parameters. 18 1.1 mrg * The entries of "table" are keyed on the domain space of the entry 19 1.1 mrg * (ignoring parameters). 20 1.1 mrg */ 21 1.1 mrg struct UNION { 22 1.1 mrg int ref; 23 1.1 mrg #ifdef HAS_TYPE 24 1.1 mrg enum isl_fold type; 25 1.1 mrg #endif 26 1.1 mrg isl_space *space; 27 1.1 mrg 28 1.1 mrg struct isl_hash_table table; 29 1.1 mrg }; 30 1.1 mrg 31 1.1 mrg /* Return the number of base expressions in "u". 32 1.1 mrg */ 33 1.1 mrg isl_size FN(FN(UNION,n),BASE)(__isl_keep UNION *u) 34 1.1 mrg { 35 1.1 mrg return u ? u->table.n : isl_size_error; 36 1.1 mrg } 37 1.1 mrg 38 1.1 mrg S(UNION,foreach_data) 39 1.1 mrg { 40 1.1 mrg isl_stat (*fn)(__isl_take PART *part, void *user); 41 1.1 mrg void *user; 42 1.1 mrg }; 43 1.1 mrg 44 1.1 mrg static isl_stat FN(UNION,call_on_copy)(void **entry, void *user) 45 1.1 mrg { 46 1.1 mrg PART *part = *entry; 47 1.1 mrg S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user; 48 1.1 mrg 49 1.1 mrg part = FN(PART,copy)(part); 50 1.1 mrg if (!part) 51 1.1 mrg return isl_stat_error; 52 1.1 mrg return data->fn(part, data->user); 53 1.1 mrg } 54 1.1 mrg 55 1.1 mrg isl_stat FN(FN(UNION,foreach),BASE)(__isl_keep UNION *u, 56 1.1 mrg isl_stat (*fn)(__isl_take PART *part, void *user), void *user) 57 1.1 mrg { 58 1.1 mrg S(UNION,foreach_data) data = { fn, user }; 59 1.1 mrg 60 1.1 mrg if (!u) 61 1.1 mrg return isl_stat_error; 62 1.1 mrg 63 1.1 mrg return isl_hash_table_foreach(u->space->ctx, &u->table, 64 1.1 mrg &FN(UNION,call_on_copy), &data); 65 1.1 mrg } 66 1.1 mrg 67 1.1 mrg /* Is the domain space of "entry" equal to the domain of "space", 68 1.1 mrg * ignoring parameters? 69 1.1 mrg */ 70 1.1 mrg static isl_bool FN(UNION,has_same_domain_space_tuples)(const void *entry, 71 1.1 mrg const void *val) 72 1.1 mrg { 73 1.1 mrg PART *part = (PART *)entry; 74 1.1 mrg isl_space *space = (isl_space *) val; 75 1.1 mrg 76 1.1 mrg if (isl_space_is_set(space)) 77 1.1 mrg return isl_space_is_set(part->dim); 78 1.1 mrg 79 1.1 mrg return isl_space_tuple_is_equal(part->dim, isl_dim_in, 80 1.1 mrg space, isl_dim_in); 81 1.1 mrg } 82 1.1 mrg 83 1.1 mrg /* Return the entry, if any, in "u" that lives in "space". 84 1.1 mrg * If "reserve" is set, then an entry is created if it does not exist yet. 85 1.1 mrg * Return NULL on error and isl_hash_table_entry_none if no entry was found. 86 1.1 mrg * Note that when "reserve" is set, the function will never return 87 1.1 mrg * isl_hash_table_entry_none. 88 1.1 mrg * 89 1.1 mrg * First look for the entry (if any) with the same domain space. 90 1.1 mrg * If it exists, then check if the range space also matches. 91 1.1 mrg */ 92 1.1 mrg static struct isl_hash_table_entry *FN(UNION,find_part_entry)( 93 1.1 mrg __isl_keep UNION *u, __isl_keep isl_space *space, int reserve) 94 1.1 mrg { 95 1.1 mrg isl_ctx *ctx; 96 1.1 mrg uint32_t hash; 97 1.1 mrg struct isl_hash_table_entry *entry; 98 1.1 mrg isl_bool equal; 99 1.1 mrg PART *part; 100 1.1 mrg 101 1.1 mrg if (!u || !space) 102 1.1 mrg return NULL; 103 1.1 mrg 104 1.1 mrg ctx = FN(UNION,get_ctx)(u); 105 1.1 mrg hash = isl_space_get_tuple_domain_hash(space); 106 1.1 mrg entry = isl_hash_table_find(ctx, &u->table, hash, 107 1.1 mrg &FN(UNION,has_same_domain_space_tuples), space, reserve); 108 1.1 mrg if (!entry || entry == isl_hash_table_entry_none) 109 1.1 mrg return entry; 110 1.1 mrg if (reserve && !entry->data) 111 1.1 mrg return entry; 112 1.1 mrg part = entry->data; 113 1.1 mrg equal = isl_space_tuple_is_equal(part->dim, isl_dim_out, 114 1.1 mrg space, isl_dim_out); 115 1.1 mrg if (equal < 0) 116 1.1 mrg return NULL; 117 1.1 mrg if (equal) 118 1.1 mrg return entry; 119 1.1 mrg if (!reserve) 120 1.1 mrg return isl_hash_table_entry_none; 121 1.1 mrg isl_die(FN(UNION,get_ctx)(u), isl_error_invalid, 122 1.1 mrg "union expression can only contain a single " 123 1.1 mrg "expression over a given domain", return NULL); 124 1.1 mrg } 125 1.1 mrg 126 1.1 mrg /* Remove "part_entry" from the hash table of "u". 127 1.1 mrg */ 128 1.1 mrg static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u, 129 1.1 mrg struct isl_hash_table_entry *part_entry) 130 1.1 mrg { 131 1.1 mrg isl_ctx *ctx; 132 1.1 mrg 133 1.1 mrg if (!u || !part_entry) 134 1.1 mrg return FN(UNION,free)(u); 135 1.1 mrg 136 1.1 mrg FN(PART,free)(part_entry->data); 137 1.1 mrg ctx = FN(UNION,get_ctx)(u); 138 1.1 mrg isl_hash_table_remove(ctx, &u->table, part_entry); 139 1.1 mrg 140 1.1 mrg return u; 141 1.1 mrg } 142 1.1 mrg 143 1.1 mrg /* Check that the domain of "part" is disjoint from the domain of the entries 144 1.1 mrg * in "u" that are defined on the same domain space, but have a different 145 1.1 mrg * target space. 146 1.1 mrg * Since a UNION with a single entry per domain space is not allowed 147 1.1 mrg * to contain two entries with the same domain space, there cannot be 148 1.1 mrg * any such other entry. 149 1.1 mrg */ 150 1.1 mrg static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u, 151 1.1 mrg __isl_keep PART *part) 152 1.1 mrg { 153 1.1 mrg return isl_stat_ok; 154 1.1 mrg } 155 1.1 mrg 156 1.1 mrg /* Check that the domain of "part1" is disjoint from the domain of "part2". 157 1.1 mrg * This check is performed before "part2" is added to a UNION to ensure 158 1.1 mrg * that the UNION expression remains a function. 159 1.1 mrg * Since a UNION with a single entry per domain space is not allowed 160 1.1 mrg * to contain two entries with the same domain space, fail unconditionally. 161 1.1 mrg */ 162 1.1 mrg static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1, 163 1.1 mrg __isl_keep PART *part2) 164 1.1 mrg { 165 1.1 mrg isl_die(FN(PART,get_ctx)(part1), isl_error_invalid, 166 1.1 mrg "additional part should live on separate space", 167 1.1 mrg return isl_stat_error); 168 1.1 mrg } 169 1.1 mrg 170 1.1 mrg /* Call "fn" on each part entry of "u". 171 1.1 mrg */ 172 1.1 mrg static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u, 173 1.1 mrg isl_stat (*fn)(void **part, void *user), void *user) 174 1.1 mrg { 175 1.1 mrg isl_ctx *ctx; 176 1.1 mrg 177 1.1 mrg if (!u) 178 1.1 mrg return isl_stat_error; 179 1.1 mrg ctx = FN(UNION,get_ctx)(u); 180 1.1 mrg return isl_hash_table_foreach(ctx, &u->table, fn, user); 181 1.1 mrg } 182 1.1 mrg 183 1.1 mrg static isl_bool FN(PART,has_domain_space_tuples)(__isl_keep PART *part, 184 1.1 mrg __isl_keep isl_space *space); 185 1.1 mrg 186 1.1 mrg /* Do the tuples of "space" correspond to those of the domain of "part"? 187 1.1 mrg * That is, is the domain space of "part" equal to "space", ignoring parameters? 188 1.1 mrg */ 189 1.1 mrg static isl_bool FN(UNION,has_domain_space_tuples)(const void *entry, 190 1.1 mrg const void *val) 191 1.1 mrg { 192 1.1 mrg PART *part = (PART *)entry; 193 1.1 mrg isl_space *space = (isl_space *) val; 194 1.1 mrg 195 1.1 mrg return FN(PART,has_domain_space_tuples)(part, space); 196 1.1 mrg } 197 1.1 mrg 198 1.1 mrg /* Call "fn" on each part of "u" that has domain space "space". 199 1.1 mrg * 200 1.1 mrg * Since each entry is defined over a different domain space, 201 1.1 mrg * simply look for an entry with the given domain space and 202 1.1 mrg * call "fn" on the corresponding part if there is one. 203 1.1 mrg */ 204 1.1 mrg isl_stat FN(UNION,foreach_on_domain)(__isl_keep UNION *u, 205 1.1 mrg __isl_keep isl_space *space, 206 1.1 mrg isl_stat (*fn)(__isl_take PART *part, void *user), void *user) 207 1.1 mrg { 208 1.1 mrg uint32_t hash; 209 1.1 mrg struct isl_hash_table_entry *entry; 210 1.1 mrg 211 1.1 mrg if (!u || !space) 212 1.1 mrg return isl_stat_error; 213 1.1 mrg hash = isl_space_get_tuple_hash(space); 214 1.1 mrg entry = isl_hash_table_find(FN(UNION,get_ctx)(u), &u->table, 215 1.1 mrg hash, &FN(UNION,has_domain_space_tuples), 216 1.1 mrg space, 0); 217 1.1 mrg if (!entry) 218 1.1 mrg return isl_stat_error; 219 1.1 mrg if (entry == isl_hash_table_entry_none) 220 1.1 mrg return isl_stat_ok; 221 1.1 mrg return fn(FN(PART,copy)(entry->data), user); 222 1.1 mrg } 223 1.1 mrg 224 1.1 mrg static isl_stat FN(UNION,free_u_entry)(void **entry, void *user) 225 1.1 mrg { 226 1.1 mrg PART *part = *entry; 227 1.1 mrg FN(PART,free)(part); 228 1.1 mrg return isl_stat_ok; 229 1.1 mrg } 230 1.1 mrg 231 1.1 mrg #include <isl_union_templ.c> 232