12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262 |
- /*
- * Copyright 2008-2009 Katholieke Universiteit Leuven
- * Copyright 2010 INRIA Saclay
- * Copyright 2012-2013 Ecole Normale Superieure
- * Copyright 2014 INRIA Rocquencourt
- * Copyright 2016 INRIA Paris
- * Copyright 2020 Cerebras Systems
- *
- * Use of this software is governed by the MIT license
- *
- * Written by Sven Verdoolaege, K.U.Leuven, Departement
- * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
- * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
- * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
- * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
- * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
- * B.P. 105 - 78153 Le Chesnay, France
- * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
- * CS 42112, 75589 Paris Cedex 12, France
- * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA
- */
- #include <isl_ctx_private.h>
- #include "isl_map_private.h"
- #include <isl_seq.h>
- #include <isl/options.h>
- #include "isl_tab.h"
- #include <isl_mat_private.h>
- #include <isl_local_space_private.h>
- #include <isl_val_private.h>
- #include <isl_vec_private.h>
- #include <isl_aff_private.h>
- #include <isl_equalities.h>
- #include <isl_constraint_private.h>
- #include <set_to_map.c>
- #include <set_from_map.c>
- #define STATUS_ERROR -1
- #define STATUS_REDUNDANT 1
- #define STATUS_VALID 2
- #define STATUS_SEPARATE 3
- #define STATUS_CUT 4
- #define STATUS_ADJ_EQ 5
- #define STATUS_ADJ_INEQ 6
- static int status_in(isl_int *ineq, struct isl_tab *tab)
- {
- enum isl_ineq_type type = isl_tab_ineq_type(tab, ineq);
- switch (type) {
- default:
- case isl_ineq_error: return STATUS_ERROR;
- case isl_ineq_redundant: return STATUS_VALID;
- case isl_ineq_separate: return STATUS_SEPARATE;
- case isl_ineq_cut: return STATUS_CUT;
- case isl_ineq_adj_eq: return STATUS_ADJ_EQ;
- case isl_ineq_adj_ineq: return STATUS_ADJ_INEQ;
- }
- }
- /* Compute the position of the equalities of basic map "bmap_i"
- * with respect to the basic map represented by "tab_j".
- * The resulting array has twice as many entries as the number
- * of equalities corresponding to the two inequalities to which
- * each equality corresponds.
- */
- static int *eq_status_in(__isl_keep isl_basic_map *bmap_i,
- struct isl_tab *tab_j)
- {
- int k, l;
- int *eq;
- isl_size dim;
- dim = isl_basic_map_dim(bmap_i, isl_dim_all);
- if (dim < 0)
- return NULL;
- eq = isl_calloc_array(bmap_i->ctx, int, 2 * bmap_i->n_eq);
- if (!eq)
- return NULL;
- for (k = 0; k < bmap_i->n_eq; ++k) {
- for (l = 0; l < 2; ++l) {
- isl_seq_neg(bmap_i->eq[k], bmap_i->eq[k], 1+dim);
- eq[2 * k + l] = status_in(bmap_i->eq[k], tab_j);
- if (eq[2 * k + l] == STATUS_ERROR)
- goto error;
- }
- }
- return eq;
- error:
- free(eq);
- return NULL;
- }
- /* Compute the position of the inequalities of basic map "bmap_i"
- * (also represented by "tab_i", if not NULL) with respect to the basic map
- * represented by "tab_j".
- */
- static int *ineq_status_in(__isl_keep isl_basic_map *bmap_i,
- struct isl_tab *tab_i, struct isl_tab *tab_j)
- {
- int k;
- unsigned n_eq = bmap_i->n_eq;
- int *ineq = isl_calloc_array(bmap_i->ctx, int, bmap_i->n_ineq);
- if (!ineq)
- return NULL;
- for (k = 0; k < bmap_i->n_ineq; ++k) {
- if (tab_i && isl_tab_is_redundant(tab_i, n_eq + k)) {
- ineq[k] = STATUS_REDUNDANT;
- continue;
- }
- ineq[k] = status_in(bmap_i->ineq[k], tab_j);
- if (ineq[k] == STATUS_ERROR)
- goto error;
- if (ineq[k] == STATUS_SEPARATE)
- break;
- }
- return ineq;
- error:
- free(ineq);
- return NULL;
- }
- static int any(int *con, unsigned len, int status)
- {
- int i;
- for (i = 0; i < len ; ++i)
- if (con[i] == status)
- return 1;
- return 0;
- }
- /* Return the first position of "status" in the list "con" of length "len".
- * Return -1 if there is no such entry.
- */
- static int find(int *con, unsigned len, int status)
- {
- int i;
- for (i = 0; i < len ; ++i)
- if (con[i] == status)
- return i;
- return -1;
- }
- static int count(int *con, unsigned len, int status)
- {
- int i;
- int c = 0;
- for (i = 0; i < len ; ++i)
- if (con[i] == status)
- c++;
- return c;
- }
- static int all(int *con, unsigned len, int status)
- {
- int i;
- for (i = 0; i < len ; ++i) {
- if (con[i] == STATUS_REDUNDANT)
- continue;
- if (con[i] != status)
- return 0;
- }
- return 1;
- }
- /* Internal information associated to a basic map in a map
- * that is to be coalesced by isl_map_coalesce.
- *
- * "bmap" is the basic map itself (or NULL if "removed" is set)
- * "tab" is the corresponding tableau (or NULL if "removed" is set)
- * "hull_hash" identifies the affine space in which "bmap" lives.
- * "modified" is set if this basic map may not be identical
- * to any of the basic maps in the input.
- * "removed" is set if this basic map has been removed from the map
- * "simplify" is set if this basic map may have some unknown integer
- * divisions that were not present in the input basic maps. The basic
- * map should then be simplified such that we may be able to find
- * a definition among the constraints.
- *
- * "eq" and "ineq" are only set if we are currently trying to coalesce
- * this basic map with another basic map, in which case they represent
- * the position of the inequalities of this basic map with respect to
- * the other basic map. The number of elements in the "eq" array
- * is twice the number of equalities in the "bmap", corresponding
- * to the two inequalities that make up each equality.
- */
- struct isl_coalesce_info {
- isl_basic_map *bmap;
- struct isl_tab *tab;
- uint32_t hull_hash;
- int modified;
- int removed;
- int simplify;
- int *eq;
- int *ineq;
- };
- /* Is there any (half of an) equality constraint in the description
- * of the basic map represented by "info" that
- * has position "status" with respect to the other basic map?
- */
- static int any_eq(struct isl_coalesce_info *info, int status)
- {
- isl_size n_eq;
- n_eq = isl_basic_map_n_equality(info->bmap);
- return any(info->eq, 2 * n_eq, status);
- }
- /* Is there any inequality constraint in the description
- * of the basic map represented by "info" that
- * has position "status" with respect to the other basic map?
- */
- static int any_ineq(struct isl_coalesce_info *info, int status)
- {
- isl_size n_ineq;
- n_ineq = isl_basic_map_n_inequality(info->bmap);
- return any(info->ineq, n_ineq, status);
- }
- /* Return the position of the first half on an equality constraint
- * in the description of the basic map represented by "info" that
- * has position "status" with respect to the other basic map.
- * The returned value is twice the position of the equality constraint
- * plus zero for the negative half and plus one for the positive half.
- * Return -1 if there is no such entry.
- */
- static int find_eq(struct isl_coalesce_info *info, int status)
- {
- isl_size n_eq;
- n_eq = isl_basic_map_n_equality(info->bmap);
- return find(info->eq, 2 * n_eq, status);
- }
- /* Return the position of the first inequality constraint in the description
- * of the basic map represented by "info" that
- * has position "status" with respect to the other basic map.
- * Return -1 if there is no such entry.
- */
- static int find_ineq(struct isl_coalesce_info *info, int status)
- {
- isl_size n_ineq;
- n_ineq = isl_basic_map_n_inequality(info->bmap);
- return find(info->ineq, n_ineq, status);
- }
- /* Return the number of (halves of) equality constraints in the description
- * of the basic map represented by "info" that
- * have position "status" with respect to the other basic map.
- */
- static int count_eq(struct isl_coalesce_info *info, int status)
- {
- isl_size n_eq;
- n_eq = isl_basic_map_n_equality(info->bmap);
- return count(info->eq, 2 * n_eq, status);
- }
- /* Return the number of inequality constraints in the description
- * of the basic map represented by "info" that
- * have position "status" with respect to the other basic map.
- */
- static int count_ineq(struct isl_coalesce_info *info, int status)
- {
- isl_size n_ineq;
- n_ineq = isl_basic_map_n_inequality(info->bmap);
- return count(info->ineq, n_ineq, status);
- }
- /* Are all non-redundant constraints of the basic map represented by "info"
- * either valid or cut constraints with respect to the other basic map?
- */
- static int all_valid_or_cut(struct isl_coalesce_info *info)
- {
- int i;
- for (i = 0; i < 2 * info->bmap->n_eq; ++i) {
- if (info->eq[i] == STATUS_REDUNDANT)
- continue;
- if (info->eq[i] == STATUS_VALID)
- continue;
- if (info->eq[i] == STATUS_CUT)
- continue;
- return 0;
- }
- for (i = 0; i < info->bmap->n_ineq; ++i) {
- if (info->ineq[i] == STATUS_REDUNDANT)
- continue;
- if (info->ineq[i] == STATUS_VALID)
- continue;
- if (info->ineq[i] == STATUS_CUT)
- continue;
- return 0;
- }
- return 1;
- }
- /* Compute the hash of the (apparent) affine hull of info->bmap (with
- * the existentially quantified variables removed) and store it
- * in info->hash.
- */
- static int coalesce_info_set_hull_hash(struct isl_coalesce_info *info)
- {
- isl_basic_map *hull;
- isl_size n_div;
- hull = isl_basic_map_copy(info->bmap);
- hull = isl_basic_map_plain_affine_hull(hull);
- n_div = isl_basic_map_dim(hull, isl_dim_div);
- if (n_div < 0)
- hull = isl_basic_map_free(hull);
- hull = isl_basic_map_drop_constraints_involving_dims(hull,
- isl_dim_div, 0, n_div);
- info->hull_hash = isl_basic_map_get_hash(hull);
- isl_basic_map_free(hull);
- return hull ? 0 : -1;
- }
- /* Free all the allocated memory in an array
- * of "n" isl_coalesce_info elements.
- */
- static void clear_coalesce_info(int n, struct isl_coalesce_info *info)
- {
- int i;
- if (!info)
- return;
- for (i = 0; i < n; ++i) {
- isl_basic_map_free(info[i].bmap);
- isl_tab_free(info[i].tab);
- }
- free(info);
- }
- /* Clear the memory associated to "info".
- */
- static void clear(struct isl_coalesce_info *info)
- {
- info->bmap = isl_basic_map_free(info->bmap);
- isl_tab_free(info->tab);
- info->tab = NULL;
- }
- /* Drop the basic map represented by "info".
- * That is, clear the memory associated to the entry and
- * mark it as having been removed.
- */
- static void drop(struct isl_coalesce_info *info)
- {
- clear(info);
- info->removed = 1;
- }
- /* Exchange the information in "info1" with that in "info2".
- */
- static void exchange(struct isl_coalesce_info *info1,
- struct isl_coalesce_info *info2)
- {
- struct isl_coalesce_info info;
- info = *info1;
- *info1 = *info2;
- *info2 = info;
- }
- /* This type represents the kind of change that has been performed
- * while trying to coalesce two basic maps.
- *
- * isl_change_none: nothing was changed
- * isl_change_drop_first: the first basic map was removed
- * isl_change_drop_second: the second basic map was removed
- * isl_change_fuse: the two basic maps were replaced by a new basic map.
- */
- enum isl_change {
- isl_change_error = -1,
- isl_change_none = 0,
- isl_change_drop_first,
- isl_change_drop_second,
- isl_change_fuse,
- };
- /* Update "change" based on an interchange of the first and the second
- * basic map. That is, interchange isl_change_drop_first and
- * isl_change_drop_second.
- */
- static enum isl_change invert_change(enum isl_change change)
- {
- switch (change) {
- case isl_change_error:
- return isl_change_error;
- case isl_change_none:
- return isl_change_none;
- case isl_change_drop_first:
- return isl_change_drop_second;
- case isl_change_drop_second:
- return isl_change_drop_first;
- case isl_change_fuse:
- return isl_change_fuse;
- }
- return isl_change_error;
- }
- /* Add the valid constraints of the basic map represented by "info"
- * to "bmap". "len" is the size of the constraints.
- * If only one of the pair of inequalities that make up an equality
- * is valid, then add that inequality.
- */
- static __isl_give isl_basic_map *add_valid_constraints(
- __isl_take isl_basic_map *bmap, struct isl_coalesce_info *info,
- unsigned len)
- {
- int k, l;
- if (!bmap)
- return NULL;
- for (k = 0; k < info->bmap->n_eq; ++k) {
- if (info->eq[2 * k] == STATUS_VALID &&
- info->eq[2 * k + 1] == STATUS_VALID) {
- l = isl_basic_map_alloc_equality(bmap);
- if (l < 0)
- return isl_basic_map_free(bmap);
- isl_seq_cpy(bmap->eq[l], info->bmap->eq[k], len);
- } else if (info->eq[2 * k] == STATUS_VALID) {
- l = isl_basic_map_alloc_inequality(bmap);
- if (l < 0)
- return isl_basic_map_free(bmap);
- isl_seq_neg(bmap->ineq[l], info->bmap->eq[k], len);
- } else if (info->eq[2 * k + 1] == STATUS_VALID) {
- l = isl_basic_map_alloc_inequality(bmap);
- if (l < 0)
- return isl_basic_map_free(bmap);
- isl_seq_cpy(bmap->ineq[l], info->bmap->eq[k], len);
- }
- }
- for (k = 0; k < info->bmap->n_ineq; ++k) {
- if (info->ineq[k] != STATUS_VALID)
- continue;
- l = isl_basic_map_alloc_inequality(bmap);
- if (l < 0)
- return isl_basic_map_free(bmap);
- isl_seq_cpy(bmap->ineq[l], info->bmap->ineq[k], len);
- }
- return bmap;
- }
- /* Is "bmap" defined by a number of (non-redundant) constraints that
- * is greater than the number of constraints of basic maps i and j combined?
- * Equalities are counted as two inequalities.
- */
- static int number_of_constraints_increases(int i, int j,
- struct isl_coalesce_info *info,
- __isl_keep isl_basic_map *bmap, struct isl_tab *tab)
- {
- int k, n_old, n_new;
- n_old = 2 * info[i].bmap->n_eq + info[i].bmap->n_ineq;
- n_old += 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq;
- n_new = 2 * bmap->n_eq;
- for (k = 0; k < bmap->n_ineq; ++k)
- if (!isl_tab_is_redundant(tab, bmap->n_eq + k))
- ++n_new;
- return n_new > n_old;
- }
- /* Replace the pair of basic maps i and j by the basic map bounded
- * by the valid constraints in both basic maps and the constraints
- * in extra (if not NULL).
- * Place the fused basic map in the position that is the smallest of i and j.
- *
- * If "detect_equalities" is set, then look for equalities encoded
- * as pairs of inequalities.
- * If "check_number" is set, then the original basic maps are only
- * replaced if the total number of constraints does not increase.
- * While the number of integer divisions in the two basic maps
- * is assumed to be the same, the actual definitions may be different.
- * We only copy the definition from one of the basic maps if it is
- * the same as that of the other basic map. Otherwise, we mark
- * the integer division as unknown and simplify the basic map
- * in an attempt to recover the integer division definition.
- * If any extra constraints get introduced, then these may
- * involve integer divisions with a unit coefficient.
- * Eliminate those that do not appear with any other coefficient
- * in other constraints, to ensure they get eliminated completely,
- * improving the chances of further coalescing.
- */
- static enum isl_change fuse(int i, int j, struct isl_coalesce_info *info,
- __isl_keep isl_mat *extra, int detect_equalities, int check_number)
- {
- int k, l;
- struct isl_basic_map *fused = NULL;
- struct isl_tab *fused_tab = NULL;
- isl_size total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- unsigned extra_rows = extra ? extra->n_row : 0;
- unsigned n_eq, n_ineq;
- int simplify = 0;
- if (total < 0)
- return isl_change_error;
- if (j < i)
- return fuse(j, i, info, extra, detect_equalities, check_number);
- n_eq = info[i].bmap->n_eq + info[j].bmap->n_eq;
- n_ineq = info[i].bmap->n_ineq + info[j].bmap->n_ineq;
- fused = isl_basic_map_alloc_space(isl_space_copy(info[i].bmap->dim),
- info[i].bmap->n_div, n_eq, n_eq + n_ineq + extra_rows);
- fused = add_valid_constraints(fused, &info[i], 1 + total);
- fused = add_valid_constraints(fused, &info[j], 1 + total);
- if (!fused)
- goto error;
- if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) &&
- ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL))
- ISL_F_SET(fused, ISL_BASIC_MAP_RATIONAL);
- for (k = 0; k < info[i].bmap->n_div; ++k) {
- int l = isl_basic_map_alloc_div(fused);
- if (l < 0)
- goto error;
- if (isl_seq_eq(info[i].bmap->div[k], info[j].bmap->div[k],
- 1 + 1 + total)) {
- isl_seq_cpy(fused->div[l], info[i].bmap->div[k],
- 1 + 1 + total);
- } else {
- isl_int_set_si(fused->div[l][0], 0);
- simplify = 1;
- }
- }
- for (k = 0; k < extra_rows; ++k) {
- l = isl_basic_map_alloc_inequality(fused);
- if (l < 0)
- goto error;
- isl_seq_cpy(fused->ineq[l], extra->row[k], 1 + total);
- }
- if (detect_equalities)
- fused = isl_basic_map_detect_inequality_pairs(fused, NULL);
- fused = isl_basic_map_gauss(fused, NULL);
- if (simplify || info[j].simplify) {
- fused = isl_basic_map_simplify(fused);
- info[i].simplify = 0;
- } else if (extra_rows > 0) {
- fused = isl_basic_map_eliminate_pure_unit_divs(fused);
- }
- fused = isl_basic_map_finalize(fused);
- fused_tab = isl_tab_from_basic_map(fused, 0);
- if (isl_tab_detect_redundant(fused_tab) < 0)
- goto error;
- if (check_number &&
- number_of_constraints_increases(i, j, info, fused, fused_tab)) {
- isl_tab_free(fused_tab);
- isl_basic_map_free(fused);
- return isl_change_none;
- }
- clear(&info[i]);
- info[i].bmap = fused;
- info[i].tab = fused_tab;
- info[i].modified = 1;
- drop(&info[j]);
- return isl_change_fuse;
- error:
- isl_tab_free(fused_tab);
- isl_basic_map_free(fused);
- return isl_change_error;
- }
- /* Given a pair of basic maps i and j such that all constraints are either
- * "valid" or "cut", check if the facets corresponding to the "cut"
- * constraints of i lie entirely within basic map j.
- * If so, replace the pair by the basic map consisting of the valid
- * constraints in both basic maps.
- * Checking whether the facet lies entirely within basic map j
- * is performed by checking whether the constraints of basic map j
- * are valid for the facet. These tests are performed on a rational
- * tableau to avoid the theoretical possibility that a constraint
- * that was considered to be a cut constraint for the entire basic map i
- * happens to be considered to be a valid constraint for the facet,
- * even though it cuts off the same rational points.
- *
- * To see that we are not introducing any extra points, call the
- * two basic maps A and B and the resulting map U and let x
- * be an element of U \setminus ( A \cup B ).
- * A line connecting x with an element of A \cup B meets a facet F
- * of either A or B. Assume it is a facet of B and let c_1 be
- * the corresponding facet constraint. We have c_1(x) < 0 and
- * so c_1 is a cut constraint. This implies that there is some
- * (possibly rational) point x' satisfying the constraints of A
- * and the opposite of c_1 as otherwise c_1 would have been marked
- * valid for A. The line connecting x and x' meets a facet of A
- * in a (possibly rational) point that also violates c_1, but this
- * is impossible since all cut constraints of B are valid for all
- * cut facets of A.
- * In case F is a facet of A rather than B, then we can apply the
- * above reasoning to find a facet of B separating x from A \cup B first.
- */
- static enum isl_change check_facets(int i, int j,
- struct isl_coalesce_info *info)
- {
- int k, l;
- struct isl_tab_undo *snap, *snap2;
- unsigned n_eq = info[i].bmap->n_eq;
- snap = isl_tab_snap(info[i].tab);
- if (isl_tab_mark_rational(info[i].tab) < 0)
- return isl_change_error;
- snap2 = isl_tab_snap(info[i].tab);
- for (k = 0; k < info[i].bmap->n_ineq; ++k) {
- if (info[i].ineq[k] != STATUS_CUT)
- continue;
- if (isl_tab_select_facet(info[i].tab, n_eq + k) < 0)
- return isl_change_error;
- for (l = 0; l < info[j].bmap->n_ineq; ++l) {
- int stat;
- if (info[j].ineq[l] != STATUS_CUT)
- continue;
- stat = status_in(info[j].bmap->ineq[l], info[i].tab);
- if (stat < 0)
- return isl_change_error;
- if (stat != STATUS_VALID)
- break;
- }
- if (isl_tab_rollback(info[i].tab, snap2) < 0)
- return isl_change_error;
- if (l < info[j].bmap->n_ineq)
- break;
- }
- if (k < info[i].bmap->n_ineq) {
- if (isl_tab_rollback(info[i].tab, snap) < 0)
- return isl_change_error;
- return isl_change_none;
- }
- return fuse(i, j, info, NULL, 0, 0);
- }
- /* Check if info->bmap contains the basic map represented
- * by the tableau "tab".
- * For each equality, we check both the constraint itself
- * (as an inequality) and its negation. Make sure the
- * equality is returned to its original state before returning.
- */
- static isl_bool contains(struct isl_coalesce_info *info, struct isl_tab *tab)
- {
- int k;
- isl_size dim;
- isl_basic_map *bmap = info->bmap;
- dim = isl_basic_map_dim(bmap, isl_dim_all);
- if (dim < 0)
- return isl_bool_error;
- for (k = 0; k < bmap->n_eq; ++k) {
- int stat;
- isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim);
- stat = status_in(bmap->eq[k], tab);
- isl_seq_neg(bmap->eq[k], bmap->eq[k], 1 + dim);
- if (stat < 0)
- return isl_bool_error;
- if (stat != STATUS_VALID)
- return isl_bool_false;
- stat = status_in(bmap->eq[k], tab);
- if (stat < 0)
- return isl_bool_error;
- if (stat != STATUS_VALID)
- return isl_bool_false;
- }
- for (k = 0; k < bmap->n_ineq; ++k) {
- int stat;
- if (info->ineq[k] == STATUS_REDUNDANT)
- continue;
- stat = status_in(bmap->ineq[k], tab);
- if (stat < 0)
- return isl_bool_error;
- if (stat != STATUS_VALID)
- return isl_bool_false;
- }
- return isl_bool_true;
- }
- /* Basic map "i" has an inequality "k" that is adjacent
- * to some inequality of basic map "j". All the other inequalities
- * are valid for "j".
- * If not NULL, then "extra" contains extra wrapping constraints that are valid
- * for both "i" and "j".
- * Check if basic map "j" forms an extension of basic map "i",
- * taking into account the extra constraints, if any.
- *
- * Note that this function is only called if some of the equalities or
- * inequalities of basic map "j" do cut basic map "i". The function is
- * correct even if there are no such cut constraints, but in that case
- * the additional checks performed by this function are overkill.
- *
- * In particular, we replace constraint k, say f >= 0, by constraint
- * f <= -1, add the inequalities of "j" that are valid for "i",
- * as well as the "extra" constraints, if any,
- * and check if the result is a subset of basic map "j".
- * To improve the chances of the subset relation being detected,
- * any variable that only attains a single integer value
- * in the tableau of "i" is first fixed to that value.
- * If the result is a subset, then we know that this result is exactly equal
- * to basic map "j" since all its constraints are valid for basic map "j".
- * By combining the valid constraints of "i" (all equalities and all
- * inequalities except "k"), the valid constraints of "j" and
- * the "extra" constraints, if any, we therefore
- * obtain a basic map that is equal to their union.
- * In this case, there is no need to perform a rollback of the tableau
- * since it is going to be destroyed in fuse().
- *
- *
- * |\__ |\__
- * | \__ | \__
- * | \_ => | \__
- * |_______| _ |_________\
- *
- *
- * |\ |\
- * | \ | \
- * | \ | \
- * | | | \
- * | ||\ => | \
- * | || \ | \
- * | || | | |
- * |__||_/ |_____/
- *
- *
- * _______ _______
- * | | __ | \__
- * | ||__| => | __|
- * |_______| |_______/
- */
- static enum isl_change is_adj_ineq_extension_with_wraps(int i, int j, int k,
- struct isl_coalesce_info *info, __isl_keep isl_mat *extra)
- {
- struct isl_tab_undo *snap;
- isl_size n_eq_i, n_ineq_j, n_extra;
- isl_size total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- isl_stat r;
- isl_bool super;
- if (total < 0)
- return isl_change_error;
- n_eq_i = isl_basic_map_n_equality(info[i].bmap);
- n_ineq_j = isl_basic_map_n_inequality(info[j].bmap);
- n_extra = isl_mat_rows(extra);
- if (n_eq_i < 0 || n_ineq_j < 0 || n_extra < 0)
- return isl_change_error;
- if (isl_tab_extend_cons(info[i].tab, 1 + n_ineq_j + n_extra) < 0)
- return isl_change_error;
- snap = isl_tab_snap(info[i].tab);
- if (isl_tab_unrestrict(info[i].tab, n_eq_i + k) < 0)
- return isl_change_error;
- isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total);
- isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1);
- r = isl_tab_add_ineq(info[i].tab, info[i].bmap->ineq[k]);
- isl_seq_neg(info[i].bmap->ineq[k], info[i].bmap->ineq[k], 1 + total);
- isl_int_sub_ui(info[i].bmap->ineq[k][0], info[i].bmap->ineq[k][0], 1);
- if (r < 0)
- return isl_change_error;
- for (k = 0; k < n_ineq_j; ++k) {
- if (info[j].ineq[k] != STATUS_VALID)
- continue;
- if (isl_tab_add_ineq(info[i].tab, info[j].bmap->ineq[k]) < 0)
- return isl_change_error;
- }
- for (k = 0; k < n_extra; ++k) {
- if (isl_tab_add_ineq(info[i].tab, extra->row[k]) < 0)
- return isl_change_error;
- }
- if (isl_tab_detect_constants(info[i].tab) < 0)
- return isl_change_error;
- super = contains(&info[j], info[i].tab);
- if (super < 0)
- return isl_change_error;
- if (super)
- return fuse(i, j, info, extra, 0, 0);
- if (isl_tab_rollback(info[i].tab, snap) < 0)
- return isl_change_error;
- return isl_change_none;
- }
- /* Given an affine transformation matrix "T", does row "row" represent
- * anything other than a unit vector (possibly shifted by a constant)
- * that is not involved in any of the other rows?
- *
- * That is, if a constraint involves the variable corresponding to
- * the row, then could its preimage by "T" have any coefficients
- * that are different from those in the original constraint?
- */
- static int not_unique_unit_row(__isl_keep isl_mat *T, int row)
- {
- int i, j;
- int len = T->n_col - 1;
- i = isl_seq_first_non_zero(T->row[row] + 1, len);
- if (i < 0)
- return 1;
- if (!isl_int_is_one(T->row[row][1 + i]) &&
- !isl_int_is_negone(T->row[row][1 + i]))
- return 1;
- j = isl_seq_first_non_zero(T->row[row] + 1 + i + 1, len - (i + 1));
- if (j >= 0)
- return 1;
- for (j = 1; j < T->n_row; ++j) {
- if (j == row)
- continue;
- if (!isl_int_is_zero(T->row[j][1 + i]))
- return 1;
- }
- return 0;
- }
- /* Does inequality constraint "ineq" of "bmap" involve any of
- * the variables marked in "affected"?
- * "total" is the total number of variables, i.e., the number
- * of entries in "affected".
- */
- static isl_bool is_affected(__isl_keep isl_basic_map *bmap, int ineq,
- int *affected, int total)
- {
- int i;
- for (i = 0; i < total; ++i) {
- if (!affected[i])
- continue;
- if (!isl_int_is_zero(bmap->ineq[ineq][1 + i]))
- return isl_bool_true;
- }
- return isl_bool_false;
- }
- /* Given the compressed version of inequality constraint "ineq"
- * of info->bmap in "v", check if the constraint can be tightened,
- * where the compression is based on an equality constraint valid
- * for info->tab.
- * If so, add the tightened version of the inequality constraint
- * to info->tab. "v" may be modified by this function.
- *
- * That is, if the compressed constraint is of the form
- *
- * m f() + c >= 0
- *
- * with 0 < c < m, then it is equivalent to
- *
- * f() >= 0
- *
- * This means that c can also be subtracted from the original,
- * uncompressed constraint without affecting the integer points
- * in info->tab. Add this tightened constraint as an extra row
- * to info->tab to make this information explicitly available.
- */
- static __isl_give isl_vec *try_tightening(struct isl_coalesce_info *info,
- int ineq, __isl_take isl_vec *v)
- {
- isl_ctx *ctx;
- isl_stat r;
- if (!v)
- return NULL;
- ctx = isl_vec_get_ctx(v);
- isl_seq_gcd(v->el + 1, v->size - 1, &ctx->normalize_gcd);
- if (isl_int_is_zero(ctx->normalize_gcd) ||
- isl_int_is_one(ctx->normalize_gcd)) {
- return v;
- }
- v = isl_vec_cow(v);
- if (!v)
- return NULL;
- isl_int_fdiv_r(v->el[0], v->el[0], ctx->normalize_gcd);
- if (isl_int_is_zero(v->el[0]))
- return v;
- if (isl_tab_extend_cons(info->tab, 1) < 0)
- return isl_vec_free(v);
- isl_int_sub(info->bmap->ineq[ineq][0],
- info->bmap->ineq[ineq][0], v->el[0]);
- r = isl_tab_add_ineq(info->tab, info->bmap->ineq[ineq]);
- isl_int_add(info->bmap->ineq[ineq][0],
- info->bmap->ineq[ineq][0], v->el[0]);
- if (r < 0)
- return isl_vec_free(v);
- return v;
- }
- /* Tighten the (non-redundant) constraints on the facet represented
- * by info->tab.
- * In particular, on input, info->tab represents the result
- * of relaxing the "n" inequality constraints of info->bmap in "relaxed"
- * by one, i.e., replacing f_i >= 0 by f_i + 1 >= 0, and then
- * replacing the one at index "l" by the corresponding equality,
- * i.e., f_k + 1 = 0, with k = relaxed[l].
- *
- * Compute a variable compression from the equality constraint f_k + 1 = 0
- * and use it to tighten the other constraints of info->bmap
- * (that is, all constraints that have not been relaxed),
- * updating info->tab (and leaving info->bmap untouched).
- * The compression handles essentially two cases, one where a variable
- * is assigned a fixed value and can therefore be eliminated, and one
- * where one variable is a shifted multiple of some other variable and
- * can therefore be replaced by that multiple.
- * Gaussian elimination would also work for the first case, but for
- * the second case, the effectiveness would depend on the order
- * of the variables.
- * After compression, some of the constraints may have coefficients
- * with a common divisor. If this divisor does not divide the constant
- * term, then the constraint can be tightened.
- * The tightening is performed on the tableau info->tab by introducing
- * extra (temporary) constraints.
- *
- * Only constraints that are possibly affected by the compression are
- * considered. In particular, if the constraint only involves variables
- * that are directly mapped to a distinct set of other variables, then
- * no common divisor can be introduced and no tightening can occur.
- *
- * It is important to only consider the non-redundant constraints
- * since the facet constraint has been relaxed prior to the call
- * to this function, meaning that the constraints that were redundant
- * prior to the relaxation may no longer be redundant.
- * These constraints will be ignored in the fused result, so
- * the fusion detection should not exploit them.
- */
- static isl_stat tighten_on_relaxed_facet(struct isl_coalesce_info *info,
- int n, int *relaxed, int l)
- {
- isl_size total;
- isl_ctx *ctx;
- isl_vec *v = NULL;
- isl_mat *T;
- int i;
- int k;
- int *affected;
- k = relaxed[l];
- ctx = isl_basic_map_get_ctx(info->bmap);
- total = isl_basic_map_dim(info->bmap, isl_dim_all);
- if (total < 0)
- return isl_stat_error;
- isl_int_add_ui(info->bmap->ineq[k][0], info->bmap->ineq[k][0], 1);
- T = isl_mat_sub_alloc6(ctx, info->bmap->ineq, k, 1, 0, 1 + total);
- T = isl_mat_variable_compression(T, NULL);
- isl_int_sub_ui(info->bmap->ineq[k][0], info->bmap->ineq[k][0], 1);
- if (!T)
- return isl_stat_error;
- if (T->n_col == 0) {
- isl_mat_free(T);
- return isl_stat_ok;
- }
- affected = isl_alloc_array(ctx, int, total);
- if (!affected)
- goto error;
- for (i = 0; i < total; ++i)
- affected[i] = not_unique_unit_row(T, 1 + i);
- for (i = 0; i < info->bmap->n_ineq; ++i) {
- isl_bool handle;
- if (any(relaxed, n, i))
- continue;
- if (info->ineq[i] == STATUS_REDUNDANT)
- continue;
- handle = is_affected(info->bmap, i, affected, total);
- if (handle < 0)
- goto error;
- if (!handle)
- continue;
- v = isl_vec_alloc(ctx, 1 + total);
- if (!v)
- goto error;
- isl_seq_cpy(v->el, info->bmap->ineq[i], 1 + total);
- v = isl_vec_mat_product(v, isl_mat_copy(T));
- v = try_tightening(info, i, v);
- isl_vec_free(v);
- if (!v)
- goto error;
- }
- isl_mat_free(T);
- free(affected);
- return isl_stat_ok;
- error:
- isl_mat_free(T);
- free(affected);
- return isl_stat_error;
- }
- /* Replace the basic maps "i" and "j" by an extension of "i"
- * along the "n" inequality constraints in "relax" by one.
- * The tableau info[i].tab has already been extended.
- * Extend info[i].bmap accordingly by relaxing all constraints in "relax"
- * by one.
- * Each integer division that does not have exactly the same
- * definition in "i" and "j" is marked unknown and the basic map
- * is scheduled to be simplified in an attempt to recover
- * the integer division definition.
- * Place the extension in the position that is the smallest of i and j.
- */
- static enum isl_change extend(int i, int j, int n, int *relax,
- struct isl_coalesce_info *info)
- {
- int l;
- isl_size total;
- info[i].bmap = isl_basic_map_cow(info[i].bmap);
- total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- if (total < 0)
- return isl_change_error;
- for (l = 0; l < info[i].bmap->n_div; ++l)
- if (!isl_seq_eq(info[i].bmap->div[l],
- info[j].bmap->div[l], 1 + 1 + total)) {
- isl_int_set_si(info[i].bmap->div[l][0], 0);
- info[i].simplify = 1;
- }
- for (l = 0; l < n; ++l)
- isl_int_add_ui(info[i].bmap->ineq[relax[l]][0],
- info[i].bmap->ineq[relax[l]][0], 1);
- ISL_F_CLR(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT);
- ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_FINAL);
- drop(&info[j]);
- info[i].modified = 1;
- if (j < i)
- exchange(&info[i], &info[j]);
- return isl_change_fuse;
- }
- /* Basic map "i" has "n" inequality constraints (collected in "relax")
- * that are such that they include basic map "j" if they are relaxed
- * by one. All the other inequalities are valid for "j".
- * Check if basic map "j" forms an extension of basic map "i".
- *
- * In particular, relax the constraints in "relax", compute the corresponding
- * facets one by one and check whether each of these is included
- * in the other basic map.
- * Before testing for inclusion, the constraints on each facet
- * are tightened to increase the chance of an inclusion being detected.
- * (Adding the valid constraints of "j" to the tableau of "i", as is done
- * in is_adj_ineq_extension, may further increase those chances, but this
- * is not currently done.)
- * If each facet is included, we know that relaxing the constraints extends
- * the basic map with exactly the other basic map (we already know that this
- * other basic map is included in the extension, because all other
- * inequality constraints are valid of "j") and we can replace the
- * two basic maps by this extension.
- *
- * If any of the relaxed constraints turn out to be redundant, then bail out.
- * isl_tab_select_facet refuses to handle such constraints. It may be
- * possible to handle them anyway by making a distinction between
- * redundant constraints with a corresponding facet that still intersects
- * the set (allowing isl_tab_select_facet to handle them) and
- * those where the facet does not intersect the set (which can be ignored
- * because the empty facet is trivially included in the other disjunct).
- * However, relaxed constraints that turn out to be redundant should
- * be fairly rare and no such instance has been reported where
- * coalescing would be successful.
- * ____ _____
- * / || / |
- * / || / |
- * \ || => \ |
- * \ || \ |
- * \___|| \____|
- *
- *
- * \ |\
- * |\\ | \
- * | \\ | \
- * | | => | /
- * | / | /
- * |/ |/
- */
- static enum isl_change is_relaxed_extension(int i, int j, int n, int *relax,
- struct isl_coalesce_info *info)
- {
- int l;
- isl_bool super;
- struct isl_tab_undo *snap, *snap2;
- unsigned n_eq = info[i].bmap->n_eq;
- for (l = 0; l < n; ++l)
- if (isl_tab_is_equality(info[i].tab, n_eq + relax[l]))
- return isl_change_none;
- snap = isl_tab_snap(info[i].tab);
- for (l = 0; l < n; ++l)
- if (isl_tab_relax(info[i].tab, n_eq + relax[l]) < 0)
- return isl_change_error;
- for (l = 0; l < n; ++l) {
- if (!isl_tab_is_redundant(info[i].tab, n_eq + relax[l]))
- continue;
- if (isl_tab_rollback(info[i].tab, snap) < 0)
- return isl_change_error;
- return isl_change_none;
- }
- snap2 = isl_tab_snap(info[i].tab);
- for (l = 0; l < n; ++l) {
- if (isl_tab_rollback(info[i].tab, snap2) < 0)
- return isl_change_error;
- if (isl_tab_select_facet(info[i].tab, n_eq + relax[l]) < 0)
- return isl_change_error;
- if (tighten_on_relaxed_facet(&info[i], n, relax, l) < 0)
- return isl_change_error;
- super = contains(&info[j], info[i].tab);
- if (super < 0)
- return isl_change_error;
- if (super)
- continue;
- if (isl_tab_rollback(info[i].tab, snap) < 0)
- return isl_change_error;
- return isl_change_none;
- }
- if (isl_tab_rollback(info[i].tab, snap2) < 0)
- return isl_change_error;
- return extend(i, j, n, relax, info);
- }
- /* Data structure that keeps track of the wrapping constraints
- * and of information to bound the coefficients of those constraints.
- *
- * "failed" is set if wrapping has failed.
- * bound is set if we want to apply a bound on the coefficients
- * mat contains the wrapping constraints
- * max is the bound on the coefficients (if bound is set)
- */
- struct isl_wraps {
- int failed;
- int bound;
- isl_mat *mat;
- isl_int max;
- };
- /* Update wraps->max to be greater than or equal to the coefficients
- * in the equalities and inequalities of info->bmap that can be removed
- * if we end up applying wrapping.
- */
- static isl_stat wraps_update_max(struct isl_wraps *wraps,
- struct isl_coalesce_info *info)
- {
- int k;
- isl_int max_k;
- isl_size total = isl_basic_map_dim(info->bmap, isl_dim_all);
- if (total < 0)
- return isl_stat_error;
- isl_int_init(max_k);
- for (k = 0; k < info->bmap->n_eq; ++k) {
- if (info->eq[2 * k] == STATUS_VALID &&
- info->eq[2 * k + 1] == STATUS_VALID)
- continue;
- isl_seq_abs_max(info->bmap->eq[k] + 1, total, &max_k);
- if (isl_int_abs_gt(max_k, wraps->max))
- isl_int_set(wraps->max, max_k);
- }
- for (k = 0; k < info->bmap->n_ineq; ++k) {
- if (info->ineq[k] == STATUS_VALID ||
- info->ineq[k] == STATUS_REDUNDANT)
- continue;
- isl_seq_abs_max(info->bmap->ineq[k] + 1, total, &max_k);
- if (isl_int_abs_gt(max_k, wraps->max))
- isl_int_set(wraps->max, max_k);
- }
- isl_int_clear(max_k);
- return isl_stat_ok;
- }
- /* Initialize the isl_wraps data structure.
- * If we want to bound the coefficients of the wrapping constraints,
- * we set wraps->max to the largest coefficient
- * in the equalities and inequalities that can be removed if we end up
- * applying wrapping.
- */
- static isl_stat wraps_init(struct isl_wraps *wraps, __isl_take isl_mat *mat,
- struct isl_coalesce_info *info, int i, int j)
- {
- isl_ctx *ctx;
- wraps->failed = 0;
- wraps->bound = 0;
- wraps->mat = mat;
- if (!mat)
- return isl_stat_error;
- wraps->mat->n_row = 0;
- ctx = isl_mat_get_ctx(mat);
- wraps->bound = isl_options_get_coalesce_bounded_wrapping(ctx);
- if (!wraps->bound)
- return isl_stat_ok;
- isl_int_init(wraps->max);
- isl_int_set_si(wraps->max, 0);
- if (wraps_update_max(wraps, &info[i]) < 0)
- return isl_stat_error;
- if (wraps_update_max(wraps, &info[j]) < 0)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* Free the contents of the isl_wraps data structure.
- */
- static void wraps_free(struct isl_wraps *wraps)
- {
- isl_mat_free(wraps->mat);
- if (wraps->bound)
- isl_int_clear(wraps->max);
- }
- /* Mark the wrapping as failed.
- */
- static isl_stat wraps_mark_failed(struct isl_wraps *wraps)
- {
- wraps->failed = 1;
- return isl_stat_ok;
- }
- /* Is the wrapping constraint in row "row" allowed?
- *
- * If wraps->bound is set, we check that none of the coefficients
- * is greater than wraps->max.
- */
- static int allow_wrap(struct isl_wraps *wraps, int row)
- {
- int i;
- if (!wraps->bound)
- return 1;
- for (i = 1; i < wraps->mat->n_col; ++i)
- if (isl_int_abs_gt(wraps->mat->row[row][i], wraps->max))
- return 0;
- return 1;
- }
- /* Wrap "ineq" (or its opposite if "negate" is set) around "bound"
- * to include "set" and add the result in position "w" of "wraps".
- * "len" is the total number of coefficients in "bound" and "ineq".
- * Return 1 on success, 0 on failure and -1 on error.
- * Wrapping can fail if the result of wrapping is equal to "bound"
- * or if we want to bound the sizes of the coefficients and
- * the wrapped constraint does not satisfy this bound.
- */
- static int add_wrap(struct isl_wraps *wraps, int w, isl_int *bound,
- isl_int *ineq, unsigned len, __isl_keep isl_set *set, int negate)
- {
- isl_seq_cpy(wraps->mat->row[w], bound, len);
- if (negate) {
- isl_seq_neg(wraps->mat->row[w + 1], ineq, len);
- ineq = wraps->mat->row[w + 1];
- }
- if (!isl_set_wrap_facet(set, wraps->mat->row[w], ineq))
- return -1;
- if (isl_seq_eq(wraps->mat->row[w], bound, len))
- return 0;
- if (!allow_wrap(wraps, w))
- return 0;
- return 1;
- }
- /* This function has two modes of operations.
- *
- * If "add_valid" is set, then all the constraints of info->bmap
- * (except the opposite of "bound") are valid for the other basic map.
- * In this case, attempts are made to wrap some of these valid constraints
- * to more tightly fit around "set". Only successful wrappings are recorded
- * and failed wrappings are ignored.
- *
- * If "add_valid" is not set, then some of the constraints of info->bmap
- * are not valid for the other basic map, and only those are considered
- * for wrapping. In this case all attempted wrappings need to succeed.
- * Otherwise "wraps" is marked as failed.
- * Note that the constraints that are valid for the other basic map
- * will be added to the combined basic map by default, so there is
- * no need to wrap them.
- * The caller wrap_in_facets even relies on this function not wrapping
- * any constraints that are already valid.
- *
- * Only consider constraints that are not redundant (as determined
- * by info->tab) and that are valid or invalid depending on "add_valid".
- * Wrap each constraint around "bound" such that it includes the whole
- * set "set" and append the resulting constraint to "wraps".
- * "wraps" is assumed to have been pre-allocated to the appropriate size.
- * wraps->n_row is the number of actual wrapped constraints that have
- * been added.
- * If any of the wrapping problems results in a constraint that is
- * identical to "bound", then this means that "set" is unbounded in such
- * a way that no wrapping is possible.
- * Similarly, if we want to bound the coefficients of the wrapping
- * constraints and a newly added wrapping constraint does not
- * satisfy the bound, then the wrapping is considered to have failed.
- * Note though that "wraps" is only marked failed if "add_valid" is not set.
- */
- static isl_stat add_selected_wraps(struct isl_wraps *wraps,
- struct isl_coalesce_info *info, isl_int *bound, __isl_keep isl_set *set,
- int add_valid)
- {
- int l, m;
- int w;
- int added;
- isl_basic_map *bmap = info->bmap;
- isl_size total = isl_basic_map_dim(bmap, isl_dim_all);
- unsigned len = 1 + total;
- if (total < 0)
- return isl_stat_error;
- w = wraps->mat->n_row;
- for (l = 0; l < bmap->n_ineq; ++l) {
- int is_valid = info->ineq[l] == STATUS_VALID;
- if ((!add_valid && is_valid) ||
- info->ineq[l] == STATUS_REDUNDANT)
- continue;
- if (isl_seq_is_neg(bound, bmap->ineq[l], len))
- continue;
- if (isl_seq_eq(bound, bmap->ineq[l], len))
- continue;
- if (isl_tab_is_redundant(info->tab, bmap->n_eq + l))
- continue;
- added = add_wrap(wraps, w, bound, bmap->ineq[l], len, set, 0);
- if (added < 0)
- return isl_stat_error;
- if (!added && !is_valid)
- goto unbounded;
- if (added)
- ++w;
- }
- for (l = 0; l < bmap->n_eq; ++l) {
- if (isl_seq_is_neg(bound, bmap->eq[l], len))
- continue;
- if (isl_seq_eq(bound, bmap->eq[l], len))
- continue;
- for (m = 0; m < 2; ++m) {
- if (info->eq[2 * l + m] == STATUS_VALID)
- continue;
- added = add_wrap(wraps, w, bound, bmap->eq[l], len,
- set, !m);
- if (added < 0)
- return isl_stat_error;
- if (!added)
- goto unbounded;
- ++w;
- }
- }
- wraps->mat->n_row = w;
- return isl_stat_ok;
- unbounded:
- return wraps_mark_failed(wraps);
- }
- /* For each constraint in info->bmap that is not redundant (as determined
- * by info->tab) and that is not a valid constraint for the other basic map,
- * wrap the constraint around "bound" such that it includes the whole
- * set "set" and append the resulting constraint to "wraps".
- * Note that the constraints that are valid for the other basic map
- * will be added to the combined basic map by default, so there is
- * no need to wrap them.
- * The caller wrap_in_facets even relies on this function not wrapping
- * any constraints that are already valid.
- * "wraps" is assumed to have been pre-allocated to the appropriate size.
- * wraps->n_row is the number of actual wrapped constraints that have
- * been added.
- * If any of the wrapping problems results in a constraint that is
- * identical to "bound", then this means that "set" is unbounded in such
- * a way that no wrapping is possible. If this happens then "wraps"
- * is marked as failed.
- * Similarly, if we want to bound the coefficients of the wrapping
- * constraints and a newly added wrapping constraint does not
- * satisfy the bound, then "wraps" is also marked as failed.
- */
- static isl_stat add_wraps(struct isl_wraps *wraps,
- struct isl_coalesce_info *info, isl_int *bound, __isl_keep isl_set *set)
- {
- return add_selected_wraps(wraps, info, bound, set, 0);
- }
- /* Check if the constraints in "wraps" from "first" until the last
- * are all valid for the basic set represented by "tab",
- * dropping the invalid constraints if "keep" is set and
- * marking the wrapping as failed if "keep" is not set and
- * any constraint turns out to be invalid.
- */
- static isl_stat check_wraps(struct isl_wraps *wraps, int first,
- struct isl_tab *tab, int keep)
- {
- int i;
- for (i = wraps->mat->n_row - 1; i >= first; --i) {
- enum isl_ineq_type type;
- type = isl_tab_ineq_type(tab, wraps->mat->row[i]);
- if (type == isl_ineq_error)
- return isl_stat_error;
- if (type == isl_ineq_redundant)
- continue;
- if (!keep)
- return wraps_mark_failed(wraps);
- wraps->mat = isl_mat_drop_rows(wraps->mat, i, 1);
- if (!wraps->mat)
- return isl_stat_error;
- }
- return isl_stat_ok;
- }
- /* Return a set that corresponds to the non-redundant constraints
- * (as recorded in tab) of bmap.
- *
- * It's important to remove the redundant constraints as some
- * of the other constraints may have been modified after the
- * constraints were marked redundant.
- * In particular, a constraint may have been relaxed.
- * Redundant constraints are ignored when a constraint is relaxed
- * and should therefore continue to be ignored ever after.
- * Otherwise, the relaxation might be thwarted by some of
- * these constraints.
- *
- * Update the underlying set to ensure that the dimension doesn't change.
- * Otherwise the integer divisions could get dropped if the tab
- * turns out to be empty.
- */
- static __isl_give isl_set *set_from_updated_bmap(__isl_keep isl_basic_map *bmap,
- struct isl_tab *tab)
- {
- isl_basic_set *bset;
- bmap = isl_basic_map_copy(bmap);
- bset = isl_basic_map_underlying_set(bmap);
- bset = isl_basic_set_cow(bset);
- bset = isl_basic_set_update_from_tab(bset, tab);
- return isl_set_from_basic_set(bset);
- }
- /* Does "info" have any cut constraints that are redundant?
- */
- static isl_bool has_redundant_cuts(struct isl_coalesce_info *info)
- {
- int l;
- isl_size n_eq, n_ineq;
- n_eq = isl_basic_map_n_equality(info->bmap);
- n_ineq = isl_basic_map_n_inequality(info->bmap);
- if (n_eq < 0 || n_ineq < 0)
- return isl_bool_error;
- for (l = 0; l < n_ineq; ++l) {
- int red;
- if (info->ineq[l] != STATUS_CUT)
- continue;
- red = isl_tab_is_redundant(info->tab, n_eq + l);
- if (red < 0)
- return isl_bool_error;
- if (red)
- return isl_bool_true;
- }
- return isl_bool_false;
- }
- /* Wrap some constraints of info->bmap that bound the facet defined
- * by inequality "k" around (the opposite of) this inequality to
- * include "set". "bound" may be used to store the negated inequality.
- *
- * If "add_valid" is set, then all ridges are already valid and
- * the purpose is to wrap "set" more tightly. In this case,
- * wrapping doesn't fail, although it is possible that no constraint
- * gets wrapped.
- *
- * If "add_valid" is not set, then some of the ridges are cut constraints
- * and only those are wrapped around "set".
- *
- * Since the wrapped constraints are not guaranteed to contain the whole
- * of info->bmap, we check them in check_wraps.
- * If any of the wrapped constraints turn out to be invalid, then
- * check_wraps will mark "wraps" as failed if "add_valid" is not set.
- * If "add_valid" is set, then the offending constraints are
- * simply removed.
- *
- * If the facet turns out to be empty, then no wrapping can be performed.
- * This is considered a failure, unless "add_valid" is set.
- *
- * If any of the cut constraints of info->bmap turn out
- * to be redundant with respect to other constraints
- * then these will neither be wrapped nor added directly to the result.
- * The result may therefore not be correct.
- * Skip wrapping and mark "wraps" as failed in this case.
- */
- static isl_stat add_selected_wraps_around_facet(struct isl_wraps *wraps,
- struct isl_coalesce_info *info, int k, isl_int *bound,
- __isl_keep isl_set *set, int add_valid)
- {
- isl_bool nowrap;
- struct isl_tab_undo *snap;
- int n;
- isl_size total = isl_basic_map_dim(info->bmap, isl_dim_all);
- if (total < 0)
- return isl_stat_error;
- snap = isl_tab_snap(info->tab);
- if (isl_tab_select_facet(info->tab, info->bmap->n_eq + k) < 0)
- return isl_stat_error;
- if (isl_tab_detect_redundant(info->tab) < 0)
- return isl_stat_error;
- if (info->tab->empty) {
- if (!add_valid)
- return wraps_mark_failed(wraps);
- return isl_stat_ok;
- }
- nowrap = has_redundant_cuts(info);
- if (nowrap < 0)
- return isl_stat_error;
- n = wraps->mat->n_row;
- if (!nowrap) {
- isl_seq_neg(bound, info->bmap->ineq[k], 1 + total);
- if (add_selected_wraps(wraps, info, bound, set, add_valid) < 0)
- return isl_stat_error;
- }
- if (isl_tab_rollback(info->tab, snap) < 0)
- return isl_stat_error;
- if (nowrap)
- return wraps_mark_failed(wraps);
- if (check_wraps(wraps, n, info->tab, add_valid) < 0)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* Wrap the constraints of info->bmap that bound the facet defined
- * by inequality "k" around (the opposite of) this inequality to
- * include "set". "bound" may be used to store the negated inequality.
- * If any of the wrapped constraints turn out to be invalid for info->bmap
- * itself, then mark "wraps" as failed.
- */
- static isl_stat add_wraps_around_facet(struct isl_wraps *wraps,
- struct isl_coalesce_info *info, int k, isl_int *bound,
- __isl_keep isl_set *set)
- {
- return add_selected_wraps_around_facet(wraps, info, k, bound, set, 0);
- }
- /* Wrap the (valid) constraints of info->bmap that bound the facet defined
- * by inequality "k" around (the opposite of) this inequality to
- * include "set" more tightly.
- * "bound" may be used to store the negated inequality.
- * Remove any wrapping constraints that turn out to be invalid
- * for info->bmap itself.
- */
- static isl_stat add_valid_wraps_around_facet(struct isl_wraps *wraps,
- struct isl_coalesce_info *info, int k, isl_int *bound,
- __isl_keep isl_set *set)
- {
- return add_selected_wraps_around_facet(wraps, info, k, bound, set, 1);
- }
- /* Basic map "i" has an inequality (say "k") that is adjacent
- * to some inequality of basic map "j". All the other inequalities
- * are valid for "j".
- * Check if basic map "j" forms an extension of basic map "i".
- *
- * Note that this function is only called if some of the equalities or
- * inequalities of basic map "j" do cut basic map "i". The function is
- * correct even if there are no such cut constraints, but in that case
- * the additional checks performed by this function are overkill.
- *
- * First try and wrap the ridges of "k" around "j".
- * Note that those ridges are already valid for "j",
- * but the wrapped versions may wrap "j" more tightly,
- * increasing the chances of "j" being detected as an extension of "i"
- */
- static enum isl_change is_adj_ineq_extension(int i, int j,
- struct isl_coalesce_info *info)
- {
- int k;
- enum isl_change change;
- isl_size total;
- isl_size n_eq_i, n_ineq_i;
- struct isl_wraps wraps;
- isl_ctx *ctx;
- isl_mat *mat;
- isl_vec *bound;
- isl_set *set_j;
- isl_stat r;
- k = find_ineq(&info[i], STATUS_ADJ_INEQ);
- if (k < 0)
- isl_die(isl_basic_map_get_ctx(info[i].bmap), isl_error_internal,
- "info[i].ineq should have exactly one STATUS_ADJ_INEQ",
- return isl_change_error);
- total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- n_eq_i = isl_basic_map_n_equality(info[i].bmap);
- n_ineq_i = isl_basic_map_n_inequality(info[i].bmap);
- if (total < 0 || n_eq_i < 0 || n_ineq_i < 0)
- return isl_change_error;
- set_j = set_from_updated_bmap(info[j].bmap, info[j].tab);
- ctx = isl_basic_map_get_ctx(info[i].bmap);
- bound = isl_vec_alloc(ctx, 1 + total);
- mat = isl_mat_alloc(ctx, 2 * n_eq_i + n_ineq_i, 1 + total);
- if (wraps_init(&wraps, mat, info, i, j) < 0)
- goto error;
- if (!bound || !set_j)
- goto error;
- r = add_valid_wraps_around_facet(&wraps, &info[i], k, bound->el, set_j);
- if (r < 0)
- goto error;
- change = is_adj_ineq_extension_with_wraps(i, j, k, info, wraps.mat);
- wraps_free(&wraps);
- isl_vec_free(bound);
- isl_set_free(set_j);
- return change;
- error:
- wraps_free(&wraps);
- isl_vec_free(bound);
- isl_set_free(set_j);
- return isl_change_error;
- }
- /* Both basic maps have at least one inequality with and adjacent
- * (but opposite) inequality in the other basic map.
- * Check that there are no cut constraints and that there is only
- * a single pair of adjacent inequalities.
- * If so, we can replace the pair by a single basic map described
- * by all but the pair of adjacent inequalities.
- * Any additional points introduced lie strictly between the two
- * adjacent hyperplanes and can therefore be integral.
- *
- * ____ _____
- * / ||\ / \
- * / || \ / \
- * \ || \ => \ \
- * \ || / \ /
- * \___||_/ \_____/
- *
- * The test for a single pair of adjacent inequalities is important
- * for avoiding the combination of two basic maps like the following
- *
- * /|
- * / |
- * /__|
- * _____
- * | |
- * | |
- * |___|
- *
- * If there are some cut constraints on one side, then we may
- * still be able to fuse the two basic maps, but we need to perform
- * some additional checks in is_adj_ineq_extension.
- */
- static enum isl_change check_adj_ineq(int i, int j,
- struct isl_coalesce_info *info)
- {
- int count_i, count_j;
- int cut_i, cut_j;
- count_i = count_ineq(&info[i], STATUS_ADJ_INEQ);
- count_j = count_ineq(&info[j], STATUS_ADJ_INEQ);
- if (count_i != 1 && count_j != 1)
- return isl_change_none;
- cut_i = any_eq(&info[i], STATUS_CUT) || any_ineq(&info[i], STATUS_CUT);
- cut_j = any_eq(&info[j], STATUS_CUT) || any_ineq(&info[j], STATUS_CUT);
- if (!cut_i && !cut_j && count_i == 1 && count_j == 1)
- return fuse(i, j, info, NULL, 0, 0);
- if (count_i == 1 && !cut_i)
- return is_adj_ineq_extension(i, j, info);
- if (count_j == 1 && !cut_j)
- return is_adj_ineq_extension(j, i, info);
- return isl_change_none;
- }
- /* Given a basic set i with a constraint k that is adjacent to
- * basic set j, check if we can wrap
- * both the facet corresponding to k (if "wrap_facet" is set) and basic map j
- * (always) around their ridges to include the other set.
- * If so, replace the pair of basic sets by their union.
- *
- * All constraints of i (except k) are assumed to be valid or
- * cut constraints for j.
- * Wrapping the cut constraints to include basic map j may result
- * in constraints that are no longer valid of basic map i
- * we have to check that the resulting wrapping constraints are valid for i.
- * If "wrap_facet" is not set, then all constraints of i (except k)
- * are assumed to be valid for j.
- * ____ _____
- * / | / \
- * / || / |
- * \ || => \ |
- * \ || \ |
- * \___|| \____|
- *
- */
- static enum isl_change can_wrap_in_facet(int i, int j, int k,
- struct isl_coalesce_info *info, int wrap_facet)
- {
- enum isl_change change = isl_change_none;
- struct isl_wraps wraps;
- isl_ctx *ctx;
- isl_mat *mat;
- struct isl_set *set_i = NULL;
- struct isl_set *set_j = NULL;
- struct isl_vec *bound = NULL;
- isl_size total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- if (total < 0)
- return isl_change_error;
- set_i = set_from_updated_bmap(info[i].bmap, info[i].tab);
- set_j = set_from_updated_bmap(info[j].bmap, info[j].tab);
- ctx = isl_basic_map_get_ctx(info[i].bmap);
- mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) +
- info[i].bmap->n_ineq + info[j].bmap->n_ineq,
- 1 + total);
- if (wraps_init(&wraps, mat, info, i, j) < 0)
- goto error;
- bound = isl_vec_alloc(ctx, 1 + total);
- if (!set_i || !set_j || !bound)
- goto error;
- isl_seq_cpy(bound->el, info[i].bmap->ineq[k], 1 + total);
- isl_int_add_ui(bound->el[0], bound->el[0], 1);
- isl_seq_normalize(ctx, bound->el, 1 + total);
- isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
- wraps.mat->n_row = 1;
- if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0)
- goto error;
- if (wraps.failed)
- goto unbounded;
- if (wrap_facet) {
- if (add_wraps_around_facet(&wraps, &info[i], k,
- bound->el, set_j) < 0)
- goto error;
- if (wraps.failed)
- goto unbounded;
- }
- change = fuse(i, j, info, wraps.mat, 0, 0);
- unbounded:
- wraps_free(&wraps);
- isl_set_free(set_i);
- isl_set_free(set_j);
- isl_vec_free(bound);
- return change;
- error:
- wraps_free(&wraps);
- isl_vec_free(bound);
- isl_set_free(set_i);
- isl_set_free(set_j);
- return isl_change_error;
- }
- /* Given a cut constraint t(x) >= 0 of basic map i, stored in row "w"
- * of wrap.mat, replace it by its relaxed version t(x) + 1 >= 0, and
- * add wrapping constraints to wrap.mat for all constraints
- * of basic map j that bound the part of basic map j that sticks out
- * of the cut constraint.
- * "set_i" is the underlying set of basic map i.
- * If any wrapping fails, then wraps->mat.n_row is reset to zero.
- *
- * In particular, we first intersect basic map j with t(x) + 1 = 0.
- * If the result is empty, then t(x) >= 0 was actually a valid constraint
- * (with respect to the integer points), so we add t(x) >= 0 instead.
- * Otherwise, we wrap the constraints of basic map j that are not
- * redundant in this intersection and that are not already valid
- * for basic map i over basic map i.
- * Note that it is sufficient to wrap the constraints to include
- * basic map i, because we will only wrap the constraints that do
- * not include basic map i already. The wrapped constraint will
- * therefore be more relaxed compared to the original constraint.
- * Since the original constraint is valid for basic map j, so is
- * the wrapped constraint.
- */
- static isl_stat wrap_in_facet(struct isl_wraps *wraps, int w,
- struct isl_coalesce_info *info_j, __isl_keep isl_set *set_i,
- struct isl_tab_undo *snap)
- {
- isl_int_add_ui(wraps->mat->row[w][0], wraps->mat->row[w][0], 1);
- if (isl_tab_add_eq(info_j->tab, wraps->mat->row[w]) < 0)
- return isl_stat_error;
- if (isl_tab_detect_redundant(info_j->tab) < 0)
- return isl_stat_error;
- if (info_j->tab->empty)
- isl_int_sub_ui(wraps->mat->row[w][0], wraps->mat->row[w][0], 1);
- else if (add_wraps(wraps, info_j, wraps->mat->row[w], set_i) < 0)
- return isl_stat_error;
- if (isl_tab_rollback(info_j->tab, snap) < 0)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* Given a pair of basic maps i and j such that j sticks out
- * of i at n cut constraints, each time by at most one,
- * try to compute wrapping constraints and replace the two
- * basic maps by a single basic map.
- * The other constraints of i are assumed to be valid for j.
- * "set_i" is the underlying set of basic map i.
- * "wraps" has been initialized to be of the right size.
- *
- * For each cut constraint t(x) >= 0 of i, we add the relaxed version
- * t(x) + 1 >= 0, along with wrapping constraints for all constraints
- * of basic map j that bound the part of basic map j that sticks out
- * of the cut constraint.
- *
- * If any wrapping fails, i.e., if we cannot wrap to touch
- * the union, then we give up.
- * Otherwise, the pair of basic maps is replaced by their union.
- */
- static enum isl_change try_wrap_in_facets(int i, int j,
- struct isl_coalesce_info *info, struct isl_wraps *wraps,
- __isl_keep isl_set *set_i)
- {
- int k, l, w;
- isl_size total;
- struct isl_tab_undo *snap;
- total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- if (total < 0)
- return isl_change_error;
- snap = isl_tab_snap(info[j].tab);
- for (k = 0; k < info[i].bmap->n_eq; ++k) {
- for (l = 0; l < 2; ++l) {
- if (info[i].eq[2 * k + l] != STATUS_CUT)
- continue;
- w = wraps->mat->n_row++;
- if (l == 0)
- isl_seq_neg(wraps->mat->row[w],
- info[i].bmap->eq[k], 1 + total);
- else
- isl_seq_cpy(wraps->mat->row[w],
- info[i].bmap->eq[k], 1 + total);
- if (wrap_in_facet(wraps, w, &info[j], set_i, snap) < 0)
- return isl_change_error;
- if (wraps->failed)
- return isl_change_none;
- }
- }
- for (k = 0; k < info[i].bmap->n_ineq; ++k) {
- if (info[i].ineq[k] != STATUS_CUT)
- continue;
- w = wraps->mat->n_row++;
- isl_seq_cpy(wraps->mat->row[w],
- info[i].bmap->ineq[k], 1 + total);
- if (wrap_in_facet(wraps, w, &info[j], set_i, snap) < 0)
- return isl_change_error;
- if (wraps->failed)
- return isl_change_none;
- }
- return fuse(i, j, info, wraps->mat, 0, 1);
- }
- /* Given a pair of basic maps i and j such that j sticks out
- * of i at n cut constraints, each time by at most one,
- * try to compute wrapping constraints and replace the two
- * basic maps by a single basic map.
- * The other constraints of i are assumed to be valid for j.
- *
- * The core computation is performed by try_wrap_in_facets.
- * This function simply extracts an underlying set representation
- * of basic map i and initializes the data structure for keeping
- * track of wrapping constraints.
- */
- static enum isl_change wrap_in_facets(int i, int j, int n,
- struct isl_coalesce_info *info)
- {
- enum isl_change change = isl_change_none;
- struct isl_wraps wraps;
- isl_ctx *ctx;
- isl_mat *mat;
- isl_set *set_i = NULL;
- isl_size total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- int max_wrap;
- if (total < 0)
- return isl_change_error;
- if (isl_tab_extend_cons(info[j].tab, 1) < 0)
- return isl_change_error;
- max_wrap = 1 + 2 * info[j].bmap->n_eq + info[j].bmap->n_ineq;
- max_wrap *= n;
- set_i = set_from_updated_bmap(info[i].bmap, info[i].tab);
- ctx = isl_basic_map_get_ctx(info[i].bmap);
- mat = isl_mat_alloc(ctx, max_wrap, 1 + total);
- if (wraps_init(&wraps, mat, info, i, j) < 0)
- goto error;
- if (!set_i)
- goto error;
- change = try_wrap_in_facets(i, j, info, &wraps, set_i);
- wraps_free(&wraps);
- isl_set_free(set_i);
- return change;
- error:
- wraps_free(&wraps);
- isl_set_free(set_i);
- return isl_change_error;
- }
- /* Return the effect of inequality "ineq" on the tableau "tab",
- * after relaxing the constant term of "ineq" by one.
- */
- static enum isl_ineq_type type_of_relaxed(struct isl_tab *tab, isl_int *ineq)
- {
- enum isl_ineq_type type;
- isl_int_add_ui(ineq[0], ineq[0], 1);
- type = isl_tab_ineq_type(tab, ineq);
- isl_int_sub_ui(ineq[0], ineq[0], 1);
- return type;
- }
- /* Given two basic sets i and j,
- * check if relaxing all the cut constraints of i by one turns
- * them into valid constraint for j and check if we can wrap in
- * the bits that are sticking out.
- * If so, replace the pair by their union.
- *
- * We first check if all relaxed cut inequalities of i are valid for j
- * and then try to wrap in the intersections of the relaxed cut inequalities
- * with j.
- *
- * During this wrapping, we consider the points of j that lie at a distance
- * of exactly 1 from i. In particular, we ignore the points that lie in
- * between this lower-dimensional space and the basic map i.
- * We can therefore only apply this to integer maps.
- * ____ _____
- * / ___|_ / \
- * / | | / |
- * \ | | => \ |
- * \|____| \ |
- * \___| \____/
- *
- * _____ ______
- * | ____|_ | \
- * | | | | |
- * | | | => | |
- * |_| | | |
- * |_____| \______|
- *
- * _______
- * | |
- * | |\ |
- * | | \ |
- * | | \ |
- * | | \|
- * | | \
- * | |_____\
- * | |
- * |_______|
- *
- * Wrapping can fail if the result of wrapping one of the facets
- * around its edges does not produce any new facet constraint.
- * In particular, this happens when we try to wrap in unbounded sets.
- *
- * _______________________________________________________________________
- * |
- * | ___
- * | | |
- * |_| |_________________________________________________________________
- * |___|
- *
- * The following is not an acceptable result of coalescing the above two
- * sets as it includes extra integer points.
- * _______________________________________________________________________
- * |
- * |
- * |
- * |
- * \______________________________________________________________________
- */
- static enum isl_change can_wrap_in_set(int i, int j,
- struct isl_coalesce_info *info)
- {
- int k, l;
- int n;
- isl_size total;
- if (ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_RATIONAL) ||
- ISL_F_ISSET(info[j].bmap, ISL_BASIC_MAP_RATIONAL))
- return isl_change_none;
- n = count_eq(&info[i], STATUS_CUT) + count_ineq(&info[i], STATUS_CUT);
- if (n == 0)
- return isl_change_none;
- total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- if (total < 0)
- return isl_change_error;
- for (k = 0; k < info[i].bmap->n_eq; ++k) {
- for (l = 0; l < 2; ++l) {
- enum isl_ineq_type type;
- if (info[i].eq[2 * k + l] != STATUS_CUT)
- continue;
- if (l == 0)
- isl_seq_neg(info[i].bmap->eq[k],
- info[i].bmap->eq[k], 1 + total);
- type = type_of_relaxed(info[j].tab,
- info[i].bmap->eq[k]);
- if (l == 0)
- isl_seq_neg(info[i].bmap->eq[k],
- info[i].bmap->eq[k], 1 + total);
- if (type == isl_ineq_error)
- return isl_change_error;
- if (type != isl_ineq_redundant)
- return isl_change_none;
- }
- }
- for (k = 0; k < info[i].bmap->n_ineq; ++k) {
- enum isl_ineq_type type;
- if (info[i].ineq[k] != STATUS_CUT)
- continue;
- type = type_of_relaxed(info[j].tab, info[i].bmap->ineq[k]);
- if (type == isl_ineq_error)
- return isl_change_error;
- if (type != isl_ineq_redundant)
- return isl_change_none;
- }
- return wrap_in_facets(i, j, n, info);
- }
- /* Check if either i or j has only cut constraints that can
- * be used to wrap in (a facet of) the other basic set.
- * if so, replace the pair by their union.
- */
- static enum isl_change check_wrap(int i, int j, struct isl_coalesce_info *info)
- {
- enum isl_change change = isl_change_none;
- change = can_wrap_in_set(i, j, info);
- if (change != isl_change_none)
- return change;
- change = can_wrap_in_set(j, i, info);
- return change;
- }
- /* Check if all inequality constraints of "i" that cut "j" cease
- * to be cut constraints if they are relaxed by one.
- * If so, collect the cut constraints in "list".
- * The caller is responsible for allocating "list".
- */
- static isl_bool all_cut_by_one(int i, int j, struct isl_coalesce_info *info,
- int *list)
- {
- int l, n;
- n = 0;
- for (l = 0; l < info[i].bmap->n_ineq; ++l) {
- enum isl_ineq_type type;
- if (info[i].ineq[l] != STATUS_CUT)
- continue;
- type = type_of_relaxed(info[j].tab, info[i].bmap->ineq[l]);
- if (type == isl_ineq_error)
- return isl_bool_error;
- if (type != isl_ineq_redundant)
- return isl_bool_false;
- list[n++] = l;
- }
- return isl_bool_true;
- }
- /* Given two basic maps such that "j" has at least one equality constraint
- * that is adjacent to an inequality constraint of "i" and such that "i" has
- * exactly one inequality constraint that is adjacent to an equality
- * constraint of "j", check whether "i" can be extended to include "j" or
- * whether "j" can be wrapped into "i".
- * All remaining constraints of "i" and "j" are assumed to be valid
- * or cut constraints of the other basic map.
- * However, none of the equality constraints of "i" are cut constraints.
- *
- * If "i" has any "cut" inequality constraints, then check if relaxing
- * each of them by one is sufficient for them to become valid.
- * If so, check if the inequality constraint adjacent to an equality
- * constraint of "j" along with all these cut constraints
- * can be relaxed by one to contain exactly "j".
- * Otherwise, or if this fails, check if "j" can be wrapped into "i".
- */
- static enum isl_change check_single_adj_eq(int i, int j,
- struct isl_coalesce_info *info)
- {
- enum isl_change change = isl_change_none;
- int k;
- int n_cut;
- int *relax;
- isl_ctx *ctx;
- isl_bool try_relax;
- n_cut = count_ineq(&info[i], STATUS_CUT);
- k = find_ineq(&info[i], STATUS_ADJ_EQ);
- if (n_cut > 0) {
- ctx = isl_basic_map_get_ctx(info[i].bmap);
- relax = isl_calloc_array(ctx, int, 1 + n_cut);
- if (!relax)
- return isl_change_error;
- relax[0] = k;
- try_relax = all_cut_by_one(i, j, info, relax + 1);
- if (try_relax < 0)
- change = isl_change_error;
- } else {
- try_relax = isl_bool_true;
- relax = &k;
- }
- if (try_relax && change == isl_change_none)
- change = is_relaxed_extension(i, j, 1 + n_cut, relax, info);
- if (n_cut > 0)
- free(relax);
- if (change != isl_change_none)
- return change;
- change = can_wrap_in_facet(i, j, k, info, n_cut > 0);
- return change;
- }
- /* At least one of the basic maps has an equality that is adjacent
- * to an inequality. Make sure that only one of the basic maps has
- * such an equality and that the other basic map has exactly one
- * inequality adjacent to an equality.
- * If the other basic map does not have such an inequality, then
- * check if all its constraints are either valid or cut constraints
- * and, if so, try wrapping in the first map into the second.
- * Otherwise, try to extend one basic map with the other or
- * wrap one basic map in the other.
- */
- static enum isl_change check_adj_eq(int i, int j,
- struct isl_coalesce_info *info)
- {
- if (any_eq(&info[i], STATUS_ADJ_INEQ) &&
- any_eq(&info[j], STATUS_ADJ_INEQ))
- /* ADJ EQ TOO MANY */
- return isl_change_none;
- if (any_eq(&info[i], STATUS_ADJ_INEQ))
- return check_adj_eq(j, i, info);
- /* j has an equality adjacent to an inequality in i */
- if (count_ineq(&info[i], STATUS_ADJ_EQ) != 1) {
- if (all_valid_or_cut(&info[i]))
- return can_wrap_in_set(i, j, info);
- return isl_change_none;
- }
- if (any_eq(&info[i], STATUS_CUT))
- return isl_change_none;
- if (any_ineq(&info[j], STATUS_ADJ_EQ) ||
- any_ineq(&info[i], STATUS_ADJ_INEQ) ||
- any_ineq(&info[j], STATUS_ADJ_INEQ))
- /* ADJ EQ TOO MANY */
- return isl_change_none;
- return check_single_adj_eq(i, j, info);
- }
- /* Disjunct "j" lies on a hyperplane that is adjacent to disjunct "i".
- * In particular, disjunct "i" has an inequality constraint that is adjacent
- * to a (combination of) equality constraint(s) of disjunct "j",
- * but disjunct "j" has no explicit equality constraint adjacent
- * to an inequality constraint of disjunct "i".
- *
- * Disjunct "i" is already known not to have any equality constraints
- * that are adjacent to an equality or inequality constraint.
- * Check that, other than the inequality constraint mentioned above,
- * all other constraints of disjunct "i" are valid for disjunct "j".
- * If so, try and wrap in disjunct "j".
- */
- static enum isl_change check_ineq_adj_eq(int i, int j,
- struct isl_coalesce_info *info)
- {
- int k;
- if (any_eq(&info[i], STATUS_CUT))
- return isl_change_none;
- if (any_ineq(&info[i], STATUS_CUT))
- return isl_change_none;
- if (any_ineq(&info[i], STATUS_ADJ_INEQ))
- return isl_change_none;
- if (count_ineq(&info[i], STATUS_ADJ_EQ) != 1)
- return isl_change_none;
- k = find_ineq(&info[i], STATUS_ADJ_EQ);
- return can_wrap_in_facet(i, j, k, info, 0);
- }
- /* The two basic maps lie on adjacent hyperplanes. In particular,
- * basic map "i" has an equality that lies parallel to basic map "j".
- * Check if we can wrap the facets around the parallel hyperplanes
- * to include the other set.
- *
- * We perform basically the same operations as can_wrap_in_facet,
- * except that we don't need to select a facet of one of the sets.
- * _
- * \\ \\
- * \\ => \\
- * \ \|
- *
- * If there is more than one equality of "i" adjacent to an equality of "j",
- * then the result will satisfy one or more equalities that are a linear
- * combination of these equalities. These will be encoded as pairs
- * of inequalities in the wrapping constraints and need to be made
- * explicit.
- */
- static enum isl_change check_eq_adj_eq(int i, int j,
- struct isl_coalesce_info *info)
- {
- int k;
- enum isl_change change = isl_change_none;
- int detect_equalities = 0;
- struct isl_wraps wraps;
- isl_ctx *ctx;
- isl_mat *mat;
- struct isl_set *set_i = NULL;
- struct isl_set *set_j = NULL;
- struct isl_vec *bound = NULL;
- isl_size total = isl_basic_map_dim(info[i].bmap, isl_dim_all);
- if (total < 0)
- return isl_change_error;
- if (count_eq(&info[i], STATUS_ADJ_EQ) != 1)
- detect_equalities = 1;
- k = find_eq(&info[i], STATUS_ADJ_EQ);
- set_i = set_from_updated_bmap(info[i].bmap, info[i].tab);
- set_j = set_from_updated_bmap(info[j].bmap, info[j].tab);
- ctx = isl_basic_map_get_ctx(info[i].bmap);
- mat = isl_mat_alloc(ctx, 2 * (info[i].bmap->n_eq + info[j].bmap->n_eq) +
- info[i].bmap->n_ineq + info[j].bmap->n_ineq,
- 1 + total);
- if (wraps_init(&wraps, mat, info, i, j) < 0)
- goto error;
- bound = isl_vec_alloc(ctx, 1 + total);
- if (!set_i || !set_j || !bound)
- goto error;
- if (k % 2 == 0)
- isl_seq_neg(bound->el, info[i].bmap->eq[k / 2], 1 + total);
- else
- isl_seq_cpy(bound->el, info[i].bmap->eq[k / 2], 1 + total);
- isl_int_add_ui(bound->el[0], bound->el[0], 1);
- isl_seq_cpy(wraps.mat->row[0], bound->el, 1 + total);
- wraps.mat->n_row = 1;
- if (add_wraps(&wraps, &info[j], bound->el, set_i) < 0)
- goto error;
- if (wraps.failed)
- goto unbounded;
- isl_int_sub_ui(bound->el[0], bound->el[0], 1);
- isl_seq_neg(bound->el, bound->el, 1 + total);
- isl_seq_cpy(wraps.mat->row[wraps.mat->n_row], bound->el, 1 + total);
- wraps.mat->n_row++;
- if (add_wraps(&wraps, &info[i], bound->el, set_j) < 0)
- goto error;
- if (wraps.failed)
- goto unbounded;
- change = fuse(i, j, info, wraps.mat, detect_equalities, 0);
- if (0) {
- error: change = isl_change_error;
- }
- unbounded:
- wraps_free(&wraps);
- isl_set_free(set_i);
- isl_set_free(set_j);
- isl_vec_free(bound);
- return change;
- }
- /* Initialize the "eq" and "ineq" fields of "info".
- */
- static void init_status(struct isl_coalesce_info *info)
- {
- info->eq = info->ineq = NULL;
- }
- /* Set info->eq to the positions of the equalities of info->bmap
- * with respect to the basic map represented by "tab".
- * If info->eq has already been computed, then do not compute it again.
- */
- static void set_eq_status_in(struct isl_coalesce_info *info,
- struct isl_tab *tab)
- {
- if (info->eq)
- return;
- info->eq = eq_status_in(info->bmap, tab);
- }
- /* Set info->ineq to the positions of the inequalities of info->bmap
- * with respect to the basic map represented by "tab".
- * If info->ineq has already been computed, then do not compute it again.
- */
- static void set_ineq_status_in(struct isl_coalesce_info *info,
- struct isl_tab *tab)
- {
- if (info->ineq)
- return;
- info->ineq = ineq_status_in(info->bmap, info->tab, tab);
- }
- /* Free the memory allocated by the "eq" and "ineq" fields of "info".
- * This function assumes that init_status has been called on "info" first,
- * after which the "eq" and "ineq" fields may or may not have been
- * assigned a newly allocated array.
- */
- static void clear_status(struct isl_coalesce_info *info)
- {
- free(info->eq);
- free(info->ineq);
- }
- /* Are all inequality constraints of the basic map represented by "info"
- * valid for the other basic map, except for a single constraint
- * that is adjacent to an inequality constraint of the other basic map?
- */
- static int all_ineq_valid_or_single_adj_ineq(struct isl_coalesce_info *info)
- {
- int i;
- int k = -1;
- for (i = 0; i < info->bmap->n_ineq; ++i) {
- if (info->ineq[i] == STATUS_REDUNDANT)
- continue;
- if (info->ineq[i] == STATUS_VALID)
- continue;
- if (info->ineq[i] != STATUS_ADJ_INEQ)
- return 0;
- if (k != -1)
- return 0;
- k = i;
- }
- return k != -1;
- }
- /* Basic map "i" has one or more equality constraints that separate it
- * from basic map "j". Check if it happens to be an extension
- * of basic map "j".
- * In particular, check that all constraints of "j" are valid for "i",
- * except for one inequality constraint that is adjacent
- * to an inequality constraints of "i".
- * If so, check for "i" being an extension of "j" by calling
- * is_adj_ineq_extension.
- *
- * Clean up the memory allocated for keeping track of the status
- * of the constraints before returning.
- */
- static enum isl_change separating_equality(int i, int j,
- struct isl_coalesce_info *info)
- {
- enum isl_change change = isl_change_none;
- if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) &&
- all_ineq_valid_or_single_adj_ineq(&info[j]))
- change = is_adj_ineq_extension(j, i, info);
- clear_status(&info[i]);
- clear_status(&info[j]);
- return change;
- }
- /* Check if the union of the given pair of basic maps
- * can be represented by a single basic map.
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- * The two basic maps are assumed to live in the same local space.
- * The "eq" and "ineq" fields of info[i] and info[j] are assumed
- * to have been initialized by the caller, either to NULL or
- * to valid information.
- *
- * We first check the effect of each constraint of one basic map
- * on the other basic map.
- * The constraint may be
- * redundant the constraint is redundant in its own
- * basic map and should be ignore and removed
- * in the end
- * valid all (integer) points of the other basic map
- * satisfy the constraint
- * separate no (integer) point of the other basic map
- * satisfies the constraint
- * cut some but not all points of the other basic map
- * satisfy the constraint
- * adj_eq the given constraint is adjacent (on the outside)
- * to an equality of the other basic map
- * adj_ineq the given constraint is adjacent (on the outside)
- * to an inequality of the other basic map
- *
- * We consider seven cases in which we can replace the pair by a single
- * basic map. We ignore all "redundant" constraints.
- *
- * 1. all constraints of one basic map are valid
- * => the other basic map is a subset and can be removed
- *
- * 2. all constraints of both basic maps are either "valid" or "cut"
- * and the facets corresponding to the "cut" constraints
- * of one of the basic maps lies entirely inside the other basic map
- * => the pair can be replaced by a basic map consisting
- * of the valid constraints in both basic maps
- *
- * 3. there is a single pair of adjacent inequalities
- * (all other constraints are "valid")
- * => the pair can be replaced by a basic map consisting
- * of the valid constraints in both basic maps
- *
- * 4. one basic map has a single adjacent inequality, while the other
- * constraints are "valid". The other basic map has some
- * "cut" constraints, but replacing the adjacent inequality by
- * its opposite and adding the valid constraints of the other
- * basic map results in a subset of the other basic map
- * => the pair can be replaced by a basic map consisting
- * of the valid constraints in both basic maps
- *
- * 5. there is a single adjacent pair of an inequality and an equality,
- * the other constraints of the basic map containing the inequality are
- * "valid". Moreover, if the inequality the basic map is relaxed
- * and then turned into an equality, then resulting facet lies
- * entirely inside the other basic map
- * => the pair can be replaced by the basic map containing
- * the inequality, with the inequality relaxed.
- *
- * 6. there is a single inequality adjacent to an equality,
- * the other constraints of the basic map containing the inequality are
- * "valid". Moreover, the facets corresponding to both
- * the inequality and the equality can be wrapped around their
- * ridges to include the other basic map
- * => the pair can be replaced by a basic map consisting
- * of the valid constraints in both basic maps together
- * with all wrapping constraints
- *
- * 7. one of the basic maps extends beyond the other by at most one.
- * Moreover, the facets corresponding to the cut constraints and
- * the pieces of the other basic map at offset one from these cut
- * constraints can be wrapped around their ridges to include
- * the union of the two basic maps
- * => the pair can be replaced by a basic map consisting
- * of the valid constraints in both basic maps together
- * with all wrapping constraints
- *
- * 8. the two basic maps live in adjacent hyperplanes. In principle
- * such sets can always be combined through wrapping, but we impose
- * that there is only one such pair, to avoid overeager coalescing.
- *
- * Throughout the computation, we maintain a collection of tableaus
- * corresponding to the basic maps. When the basic maps are dropped
- * or combined, the tableaus are modified accordingly.
- */
- static enum isl_change coalesce_local_pair_reuse(int i, int j,
- struct isl_coalesce_info *info)
- {
- enum isl_change change = isl_change_none;
- set_ineq_status_in(&info[i], info[j].tab);
- if (info[i].bmap->n_ineq && !info[i].ineq)
- goto error;
- if (any_ineq(&info[i], STATUS_ERROR))
- goto error;
- if (any_ineq(&info[i], STATUS_SEPARATE))
- goto done;
- set_ineq_status_in(&info[j], info[i].tab);
- if (info[j].bmap->n_ineq && !info[j].ineq)
- goto error;
- if (any_ineq(&info[j], STATUS_ERROR))
- goto error;
- if (any_ineq(&info[j], STATUS_SEPARATE))
- goto done;
- set_eq_status_in(&info[i], info[j].tab);
- if (info[i].bmap->n_eq && !info[i].eq)
- goto error;
- if (any_eq(&info[i], STATUS_ERROR))
- goto error;
- set_eq_status_in(&info[j], info[i].tab);
- if (info[j].bmap->n_eq && !info[j].eq)
- goto error;
- if (any_eq(&info[j], STATUS_ERROR))
- goto error;
- if (any_eq(&info[i], STATUS_SEPARATE))
- return separating_equality(i, j, info);
- if (any_eq(&info[j], STATUS_SEPARATE))
- return separating_equality(j, i, info);
- if (all(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_VALID) &&
- all(info[i].ineq, info[i].bmap->n_ineq, STATUS_VALID)) {
- drop(&info[j]);
- change = isl_change_drop_second;
- } else if (all(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_VALID) &&
- all(info[j].ineq, info[j].bmap->n_ineq, STATUS_VALID)) {
- drop(&info[i]);
- change = isl_change_drop_first;
- } else if (any_eq(&info[i], STATUS_ADJ_EQ)) {
- change = check_eq_adj_eq(i, j, info);
- } else if (any_eq(&info[j], STATUS_ADJ_EQ)) {
- change = check_eq_adj_eq(j, i, info);
- } else if (any_eq(&info[i], STATUS_ADJ_INEQ) ||
- any_eq(&info[j], STATUS_ADJ_INEQ)) {
- change = check_adj_eq(i, j, info);
- } else if (any_ineq(&info[i], STATUS_ADJ_EQ)) {
- change = check_ineq_adj_eq(i, j, info);
- } else if (any_ineq(&info[j], STATUS_ADJ_EQ)) {
- change = check_ineq_adj_eq(j, i, info);
- } else if (any_ineq(&info[i], STATUS_ADJ_INEQ) ||
- any_ineq(&info[j], STATUS_ADJ_INEQ)) {
- change = check_adj_ineq(i, j, info);
- } else {
- if (!any_eq(&info[i], STATUS_CUT) &&
- !any_eq(&info[j], STATUS_CUT))
- change = check_facets(i, j, info);
- if (change == isl_change_none)
- change = check_wrap(i, j, info);
- }
- done:
- clear_status(&info[i]);
- clear_status(&info[j]);
- return change;
- error:
- clear_status(&info[i]);
- clear_status(&info[j]);
- return isl_change_error;
- }
- /* Check if the union of the given pair of basic maps
- * can be represented by a single basic map.
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- * The two basic maps are assumed to live in the same local space.
- */
- static enum isl_change coalesce_local_pair(int i, int j,
- struct isl_coalesce_info *info)
- {
- init_status(&info[i]);
- init_status(&info[j]);
- return coalesce_local_pair_reuse(i, j, info);
- }
- /* Shift the integer division at position "div" of the basic map
- * represented by "info" by "shift".
- *
- * That is, if the integer division has the form
- *
- * floor(f(x)/d)
- *
- * then replace it by
- *
- * floor((f(x) + shift * d)/d) - shift
- */
- static isl_stat shift_div(struct isl_coalesce_info *info, int div,
- isl_int shift)
- {
- isl_size total, n_div;
- info->bmap = isl_basic_map_shift_div(info->bmap, div, 0, shift);
- if (!info->bmap)
- return isl_stat_error;
- total = isl_basic_map_dim(info->bmap, isl_dim_all);
- n_div = isl_basic_map_dim(info->bmap, isl_dim_div);
- if (total < 0 || n_div < 0)
- return isl_stat_error;
- total -= n_div;
- if (isl_tab_shift_var(info->tab, total + div, shift) < 0)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* If the integer division at position "div" is defined by an equality,
- * i.e., a stride constraint, then change the integer division expression
- * to have a constant term equal to zero.
- *
- * Let the equality constraint be
- *
- * c + f + m a = 0
- *
- * The integer division expression is then typically of the form
- *
- * a = floor((-f - c')/m)
- *
- * The integer division is first shifted by t = floor(c/m),
- * turning the equality constraint into
- *
- * c - m floor(c/m) + f + m a' = 0
- *
- * i.e.,
- *
- * (c mod m) + f + m a' = 0
- *
- * That is,
- *
- * a' = (-f - (c mod m))/m = floor((-f)/m)
- *
- * because a' is an integer and 0 <= (c mod m) < m.
- * The constant term of a' can therefore be zeroed out,
- * but only if the integer division expression is of the expected form.
- */
- static isl_stat normalize_stride_div(struct isl_coalesce_info *info, int div)
- {
- isl_bool defined, valid;
- isl_stat r;
- isl_constraint *c;
- isl_int shift, stride;
- defined = isl_basic_map_has_defining_equality(info->bmap, isl_dim_div,
- div, &c);
- if (defined < 0)
- return isl_stat_error;
- if (!defined)
- return isl_stat_ok;
- if (!c)
- return isl_stat_error;
- valid = isl_constraint_is_div_equality(c, div);
- isl_int_init(shift);
- isl_int_init(stride);
- isl_constraint_get_constant(c, &shift);
- isl_constraint_get_coefficient(c, isl_dim_div, div, &stride);
- isl_int_fdiv_q(shift, shift, stride);
- r = shift_div(info, div, shift);
- isl_int_clear(stride);
- isl_int_clear(shift);
- isl_constraint_free(c);
- if (r < 0 || valid < 0)
- return isl_stat_error;
- if (!valid)
- return isl_stat_ok;
- info->bmap = isl_basic_map_set_div_expr_constant_num_si_inplace(
- info->bmap, div, 0);
- if (!info->bmap)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* The basic maps represented by "info1" and "info2" are known
- * to have the same number of integer divisions.
- * Check if pairs of integer divisions are equal to each other
- * despite the fact that they differ by a rational constant.
- *
- * In particular, look for any pair of integer divisions that
- * only differ in their constant terms.
- * If either of these integer divisions is defined
- * by stride constraints, then modify it to have a zero constant term.
- * If both are defined by stride constraints then in the end they will have
- * the same (zero) constant term.
- */
- static isl_stat harmonize_stride_divs(struct isl_coalesce_info *info1,
- struct isl_coalesce_info *info2)
- {
- int i;
- isl_size n;
- n = isl_basic_map_dim(info1->bmap, isl_dim_div);
- if (n < 0)
- return isl_stat_error;
- for (i = 0; i < n; ++i) {
- isl_bool known, harmonize;
- known = isl_basic_map_div_is_known(info1->bmap, i);
- if (known >= 0 && known)
- known = isl_basic_map_div_is_known(info2->bmap, i);
- if (known < 0)
- return isl_stat_error;
- if (!known)
- continue;
- harmonize = isl_basic_map_equal_div_expr_except_constant(
- info1->bmap, i, info2->bmap, i);
- if (harmonize < 0)
- return isl_stat_error;
- if (!harmonize)
- continue;
- if (normalize_stride_div(info1, i) < 0)
- return isl_stat_error;
- if (normalize_stride_div(info2, i) < 0)
- return isl_stat_error;
- }
- return isl_stat_ok;
- }
- /* If "shift" is an integer constant, then shift the integer division
- * at position "div" of the basic map represented by "info" by "shift".
- * If "shift" is not an integer constant, then do nothing.
- * If "shift" is equal to zero, then no shift needs to be performed either.
- *
- * That is, if the integer division has the form
- *
- * floor(f(x)/d)
- *
- * then replace it by
- *
- * floor((f(x) + shift * d)/d) - shift
- */
- static isl_stat shift_if_cst_int(struct isl_coalesce_info *info, int div,
- __isl_keep isl_aff *shift)
- {
- isl_bool cst;
- isl_stat r;
- isl_int d;
- isl_val *c;
- cst = isl_aff_is_cst(shift);
- if (cst < 0 || !cst)
- return cst < 0 ? isl_stat_error : isl_stat_ok;
- c = isl_aff_get_constant_val(shift);
- cst = isl_val_is_int(c);
- if (cst >= 0 && cst)
- cst = isl_bool_not(isl_val_is_zero(c));
- if (cst < 0 || !cst) {
- isl_val_free(c);
- return cst < 0 ? isl_stat_error : isl_stat_ok;
- }
- isl_int_init(d);
- r = isl_val_get_num_isl_int(c, &d);
- if (r >= 0)
- r = shift_div(info, div, d);
- isl_int_clear(d);
- isl_val_free(c);
- return r;
- }
- /* Check if some of the divs in the basic map represented by "info1"
- * are shifts of the corresponding divs in the basic map represented
- * by "info2", taking into account the equality constraints "eq1" of "info1"
- * and "eq2" of "info2". If so, align them with those of "info2".
- * "info1" and "info2" are assumed to have the same number
- * of integer divisions.
- *
- * An integer division is considered to be a shift of another integer
- * division if, after simplification with respect to the equality
- * constraints of the other basic map, one is equal to the other
- * plus a constant.
- *
- * In particular, for each pair of integer divisions, if both are known,
- * have the same denominator and are not already equal to each other,
- * simplify each with respect to the equality constraints
- * of the other basic map. If the difference is an integer constant,
- * then move this difference outside.
- * That is, if, after simplification, one integer division is of the form
- *
- * floor((f(x) + c_1)/d)
- *
- * while the other is of the form
- *
- * floor((f(x) + c_2)/d)
- *
- * and n = (c_2 - c_1)/d is an integer, then replace the first
- * integer division by
- *
- * floor((f_1(x) + c_1 + n * d)/d) - n,
- *
- * where floor((f_1(x) + c_1 + n * d)/d) = floor((f2(x) + c_2)/d)
- * after simplification with respect to the equality constraints.
- */
- static isl_stat harmonize_divs_with_hulls(struct isl_coalesce_info *info1,
- struct isl_coalesce_info *info2, __isl_keep isl_basic_set *eq1,
- __isl_keep isl_basic_set *eq2)
- {
- int i;
- isl_size total;
- isl_local_space *ls1, *ls2;
- total = isl_basic_map_dim(info1->bmap, isl_dim_all);
- if (total < 0)
- return isl_stat_error;
- ls1 = isl_local_space_wrap(isl_basic_map_get_local_space(info1->bmap));
- ls2 = isl_local_space_wrap(isl_basic_map_get_local_space(info2->bmap));
- for (i = 0; i < info1->bmap->n_div; ++i) {
- isl_stat r;
- isl_aff *div1, *div2;
- if (!isl_local_space_div_is_known(ls1, i) ||
- !isl_local_space_div_is_known(ls2, i))
- continue;
- if (isl_int_ne(info1->bmap->div[i][0], info2->bmap->div[i][0]))
- continue;
- if (isl_seq_eq(info1->bmap->div[i] + 1,
- info2->bmap->div[i] + 1, 1 + total))
- continue;
- div1 = isl_local_space_get_div(ls1, i);
- div2 = isl_local_space_get_div(ls2, i);
- div1 = isl_aff_substitute_equalities(div1,
- isl_basic_set_copy(eq2));
- div2 = isl_aff_substitute_equalities(div2,
- isl_basic_set_copy(eq1));
- div2 = isl_aff_sub(div2, div1);
- r = shift_if_cst_int(info1, i, div2);
- isl_aff_free(div2);
- if (r < 0)
- break;
- }
- isl_local_space_free(ls1);
- isl_local_space_free(ls2);
- if (i < info1->bmap->n_div)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* Check if some of the divs in the basic map represented by "info1"
- * are shifts of the corresponding divs in the basic map represented
- * by "info2". If so, align them with those of "info2".
- * Only do this if "info1" and "info2" have the same number
- * of integer divisions.
- *
- * An integer division is considered to be a shift of another integer
- * division if, after simplification with respect to the equality
- * constraints of the other basic map, one is equal to the other
- * plus a constant.
- *
- * First check if pairs of integer divisions are equal to each other
- * despite the fact that they differ by a rational constant.
- * If so, try and arrange for them to have the same constant term.
- *
- * Then, extract the equality constraints and continue with
- * harmonize_divs_with_hulls.
- *
- * If the equality constraints of both basic maps are the same,
- * then there is no need to perform any shifting since
- * the coefficients of the integer divisions should have been
- * reduced in the same way.
- */
- static isl_stat harmonize_divs(struct isl_coalesce_info *info1,
- struct isl_coalesce_info *info2)
- {
- isl_bool equal;
- isl_basic_map *bmap1, *bmap2;
- isl_basic_set *eq1, *eq2;
- isl_stat r;
- if (!info1->bmap || !info2->bmap)
- return isl_stat_error;
- if (info1->bmap->n_div != info2->bmap->n_div)
- return isl_stat_ok;
- if (info1->bmap->n_div == 0)
- return isl_stat_ok;
- if (harmonize_stride_divs(info1, info2) < 0)
- return isl_stat_error;
- bmap1 = isl_basic_map_copy(info1->bmap);
- bmap2 = isl_basic_map_copy(info2->bmap);
- eq1 = isl_basic_map_wrap(isl_basic_map_plain_affine_hull(bmap1));
- eq2 = isl_basic_map_wrap(isl_basic_map_plain_affine_hull(bmap2));
- equal = isl_basic_set_plain_is_equal(eq1, eq2);
- if (equal < 0)
- r = isl_stat_error;
- else if (equal)
- r = isl_stat_ok;
- else
- r = harmonize_divs_with_hulls(info1, info2, eq1, eq2);
- isl_basic_set_free(eq1);
- isl_basic_set_free(eq2);
- return r;
- }
- /* Do the two basic maps live in the same local space, i.e.,
- * do they have the same (known) divs?
- * If either basic map has any unknown divs, then we can only assume
- * that they do not live in the same local space.
- */
- static isl_bool same_divs(__isl_keep isl_basic_map *bmap1,
- __isl_keep isl_basic_map *bmap2)
- {
- int i;
- isl_bool known;
- isl_size total;
- if (!bmap1 || !bmap2)
- return isl_bool_error;
- if (bmap1->n_div != bmap2->n_div)
- return isl_bool_false;
- if (bmap1->n_div == 0)
- return isl_bool_true;
- known = isl_basic_map_divs_known(bmap1);
- if (known < 0 || !known)
- return known;
- known = isl_basic_map_divs_known(bmap2);
- if (known < 0 || !known)
- return known;
- total = isl_basic_map_dim(bmap1, isl_dim_all);
- if (total < 0)
- return isl_bool_error;
- for (i = 0; i < bmap1->n_div; ++i)
- if (!isl_seq_eq(bmap1->div[i], bmap2->div[i], 2 + total))
- return isl_bool_false;
- return isl_bool_true;
- }
- /* Assuming that "tab" contains the equality constraints and
- * the initial inequality constraints of "bmap", copy the remaining
- * inequality constraints of "bmap" to "Tab".
- */
- static isl_stat copy_ineq(struct isl_tab *tab, __isl_keep isl_basic_map *bmap)
- {
- int i, n_ineq;
- if (!bmap)
- return isl_stat_error;
- n_ineq = tab->n_con - tab->n_eq;
- for (i = n_ineq; i < bmap->n_ineq; ++i)
- if (isl_tab_add_ineq(tab, bmap->ineq[i]) < 0)
- return isl_stat_error;
- return isl_stat_ok;
- }
- /* Description of an integer division that is added
- * during an expansion.
- * "pos" is the position of the corresponding variable.
- * "cst" indicates whether this integer division has a fixed value.
- * "val" contains the fixed value, if the value is fixed.
- */
- struct isl_expanded {
- int pos;
- isl_bool cst;
- isl_int val;
- };
- /* For each of the "n" integer division variables "expanded",
- * if the variable has a fixed value, then add two inequality
- * constraints expressing the fixed value.
- * Otherwise, add the corresponding div constraints.
- * The caller is responsible for removing the div constraints
- * that it added for all these "n" integer divisions.
- *
- * The div constraints and the pair of inequality constraints
- * forcing the fixed value cannot both be added for a given variable
- * as the combination may render some of the original constraints redundant.
- * These would then be ignored during the coalescing detection,
- * while they could remain in the fused result.
- *
- * The two added inequality constraints are
- *
- * -a + v >= 0
- * a - v >= 0
- *
- * with "a" the variable and "v" its fixed value.
- * The facet corresponding to one of these two constraints is selected
- * in the tableau to ensure that the pair of inequality constraints
- * is treated as an equality constraint.
- *
- * The information in info->ineq is thrown away because it was
- * computed in terms of div constraints, while some of those
- * have now been replaced by these pairs of inequality constraints.
- */
- static isl_stat fix_constant_divs(struct isl_coalesce_info *info,
- int n, struct isl_expanded *expanded)
- {
- unsigned o_div;
- int i;
- isl_vec *ineq;
- o_div = isl_basic_map_offset(info->bmap, isl_dim_div) - 1;
- ineq = isl_vec_alloc(isl_tab_get_ctx(info->tab), 1 + info->tab->n_var);
- if (!ineq)
- return isl_stat_error;
- isl_seq_clr(ineq->el + 1, info->tab->n_var);
- for (i = 0; i < n; ++i) {
- if (!expanded[i].cst) {
- info->bmap = isl_basic_map_extend_constraints(
- info->bmap, 0, 2);
- info->bmap = isl_basic_map_add_div_constraints(
- info->bmap, expanded[i].pos - o_div);
- } else {
- isl_int_set_si(ineq->el[1 + expanded[i].pos], -1);
- isl_int_set(ineq->el[0], expanded[i].val);
- info->bmap = isl_basic_map_add_ineq(info->bmap,
- ineq->el);
- isl_int_set_si(ineq->el[1 + expanded[i].pos], 1);
- isl_int_neg(ineq->el[0], expanded[i].val);
- info->bmap = isl_basic_map_add_ineq(info->bmap,
- ineq->el);
- isl_int_set_si(ineq->el[1 + expanded[i].pos], 0);
- }
- if (copy_ineq(info->tab, info->bmap) < 0)
- break;
- if (expanded[i].cst &&
- isl_tab_select_facet(info->tab, info->tab->n_con - 1) < 0)
- break;
- }
- isl_vec_free(ineq);
- clear_status(info);
- init_status(info);
- return i < n ? isl_stat_error : isl_stat_ok;
- }
- /* Insert the "n" integer division variables "expanded"
- * into info->tab and info->bmap and
- * update info->ineq with respect to the redundant constraints
- * in the resulting tableau.
- * "bmap" contains the result of this insertion in info->bmap,
- * while info->bmap is the original version
- * of "bmap", i.e., the one that corresponds to the current
- * state of info->tab. The number of constraints in info->bmap
- * is assumed to be the same as the number of constraints
- * in info->tab. This is required to be able to detect
- * the extra constraints in "bmap".
- *
- * In particular, introduce extra variables corresponding
- * to the extra integer divisions and add the div constraints
- * that were added to "bmap" after info->tab was created
- * from info->bmap.
- * Furthermore, check if these extra integer divisions happen
- * to attain a fixed integer value in info->tab.
- * If so, replace the corresponding div constraints by pairs
- * of inequality constraints that fix these
- * integer divisions to their single integer values.
- * Replace info->bmap by "bmap" to match the changes to info->tab.
- * info->ineq was computed without a tableau and therefore
- * does not take into account the redundant constraints
- * in the tableau. Mark them here.
- * There is no need to check the newly added div constraints
- * since they cannot be redundant.
- * The redundancy check is not performed when constants have been discovered
- * since info->ineq is completely thrown away in this case.
- */
- static isl_stat tab_insert_divs(struct isl_coalesce_info *info,
- int n, struct isl_expanded *expanded, __isl_take isl_basic_map *bmap)
- {
- int i, n_ineq;
- unsigned n_eq;
- struct isl_tab_undo *snap;
- int any;
- if (!bmap)
- return isl_stat_error;
- if (info->bmap->n_eq + info->bmap->n_ineq != info->tab->n_con)
- isl_die(isl_basic_map_get_ctx(bmap), isl_error_internal,
- "original tableau does not correspond "
- "to original basic map", goto error);
- if (isl_tab_extend_vars(info->tab, n) < 0)
- goto error;
- if (isl_tab_extend_cons(info->tab, 2 * n) < 0)
- goto error;
- for (i = 0; i < n; ++i) {
- if (isl_tab_insert_var(info->tab, expanded[i].pos) < 0)
- goto error;
- }
- snap = isl_tab_snap(info->tab);
- n_ineq = info->tab->n_con - info->tab->n_eq;
- if (copy_ineq(info->tab, bmap) < 0)
- goto error;
- isl_basic_map_free(info->bmap);
- info->bmap = bmap;
- any = 0;
- for (i = 0; i < n; ++i) {
- expanded[i].cst = isl_tab_is_constant(info->tab,
- expanded[i].pos, &expanded[i].val);
- if (expanded[i].cst < 0)
- return isl_stat_error;
- if (expanded[i].cst)
- any = 1;
- }
- if (any) {
- if (isl_tab_rollback(info->tab, snap) < 0)
- return isl_stat_error;
- info->bmap = isl_basic_map_cow(info->bmap);
- info->bmap = isl_basic_map_free_inequality(info->bmap, 2 * n);
- if (info->bmap < 0)
- return isl_stat_error;
- return fix_constant_divs(info, n, expanded);
- }
- n_eq = info->bmap->n_eq;
- for (i = 0; i < n_ineq; ++i) {
- if (isl_tab_is_redundant(info->tab, n_eq + i))
- info->ineq[i] = STATUS_REDUNDANT;
- }
- return isl_stat_ok;
- error:
- isl_basic_map_free(bmap);
- return isl_stat_error;
- }
- /* Expand info->tab and info->bmap in the same way "bmap" was expanded
- * in isl_basic_map_expand_divs using the expansion "exp" and
- * update info->ineq with respect to the redundant constraints
- * in the resulting tableau. info->bmap is the original version
- * of "bmap", i.e., the one that corresponds to the current
- * state of info->tab. The number of constraints in info->bmap
- * is assumed to be the same as the number of constraints
- * in info->tab. This is required to be able to detect
- * the extra constraints in "bmap".
- *
- * Extract the positions where extra local variables are introduced
- * from "exp" and call tab_insert_divs.
- */
- static isl_stat expand_tab(struct isl_coalesce_info *info, int *exp,
- __isl_take isl_basic_map *bmap)
- {
- isl_ctx *ctx;
- struct isl_expanded *expanded;
- int i, j, k, n;
- int extra_var;
- isl_size total, n_div;
- unsigned pos;
- isl_stat r;
- total = isl_basic_map_dim(bmap, isl_dim_all);
- n_div = isl_basic_map_dim(bmap, isl_dim_div);
- if (total < 0 || n_div < 0)
- return isl_stat_error;
- pos = total - n_div;
- extra_var = total - info->tab->n_var;
- n = n_div - extra_var;
- ctx = isl_basic_map_get_ctx(bmap);
- expanded = isl_calloc_array(ctx, struct isl_expanded, extra_var);
- if (extra_var && !expanded)
- goto error;
- i = 0;
- k = 0;
- for (j = 0; j < n_div; ++j) {
- if (i < n && exp[i] == j) {
- ++i;
- continue;
- }
- expanded[k++].pos = pos + j;
- }
- for (k = 0; k < extra_var; ++k)
- isl_int_init(expanded[k].val);
- r = tab_insert_divs(info, extra_var, expanded, bmap);
- for (k = 0; k < extra_var; ++k)
- isl_int_clear(expanded[k].val);
- free(expanded);
- return r;
- error:
- isl_basic_map_free(bmap);
- return isl_stat_error;
- }
- /* Check if the union of the basic maps represented by info[i] and info[j]
- * can be represented by a single basic map,
- * after expanding the divs of info[i] to match those of info[j].
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- *
- * The caller has already checked for info[j] being a subset of info[i].
- * If some of the divs of info[j] are unknown, then the expanded info[i]
- * will not have the corresponding div constraints. The other patterns
- * therefore cannot apply. Skip the computation in this case.
- *
- * The expansion is performed using the divs "div" and expansion "exp"
- * computed by the caller.
- * info[i].bmap has already been expanded and the result is passed in
- * as "bmap".
- * The "eq" and "ineq" fields of info[i] reflect the status of
- * the constraints of the expanded "bmap" with respect to info[j].tab.
- * However, inequality constraints that are redundant in info[i].tab
- * have not yet been marked as such because no tableau was available.
- *
- * Replace info[i].bmap by "bmap" and expand info[i].tab as well,
- * updating info[i].ineq with respect to the redundant constraints.
- * Then try and coalesce the expanded info[i] with info[j],
- * reusing the information in info[i].eq and info[i].ineq.
- * If this does not result in any coalescing or if it results in info[j]
- * getting dropped (which should not happen in practice, since the case
- * of info[j] being a subset of info[i] has already been checked by
- * the caller), then revert info[i] to its original state.
- */
- static enum isl_change coalesce_expand_tab_divs(__isl_take isl_basic_map *bmap,
- int i, int j, struct isl_coalesce_info *info, __isl_keep isl_mat *div,
- int *exp)
- {
- isl_bool known;
- isl_basic_map *bmap_i;
- struct isl_tab_undo *snap;
- enum isl_change change = isl_change_none;
- known = isl_basic_map_divs_known(info[j].bmap);
- if (known < 0 || !known) {
- clear_status(&info[i]);
- isl_basic_map_free(bmap);
- return known < 0 ? isl_change_error : isl_change_none;
- }
- bmap_i = isl_basic_map_copy(info[i].bmap);
- snap = isl_tab_snap(info[i].tab);
- if (expand_tab(&info[i], exp, bmap) < 0)
- change = isl_change_error;
- init_status(&info[j]);
- if (change == isl_change_none)
- change = coalesce_local_pair_reuse(i, j, info);
- else
- clear_status(&info[i]);
- if (change != isl_change_none && change != isl_change_drop_second) {
- isl_basic_map_free(bmap_i);
- } else {
- isl_basic_map_free(info[i].bmap);
- info[i].bmap = bmap_i;
- if (isl_tab_rollback(info[i].tab, snap) < 0)
- change = isl_change_error;
- }
- return change;
- }
- /* Check if the union of "bmap" and the basic map represented by info[j]
- * can be represented by a single basic map,
- * after expanding the divs of "bmap" to match those of info[j].
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- *
- * In particular, check if the expanded "bmap" contains the basic map
- * represented by the tableau info[j].tab.
- * The expansion is performed using the divs "div" and expansion "exp"
- * computed by the caller.
- * Then we check if all constraints of the expanded "bmap" are valid for
- * info[j].tab.
- *
- * If "i" is not equal to -1, then "bmap" is equal to info[i].bmap.
- * In this case, the positions of the constraints of info[i].bmap
- * with respect to the basic map represented by info[j] are stored
- * in info[i].
- *
- * If the expanded "bmap" does not contain the basic map
- * represented by the tableau info[j].tab and if "i" is not -1,
- * i.e., if the original "bmap" is info[i].bmap, then expand info[i].tab
- * as well and check if that results in coalescing.
- */
- static enum isl_change coalesce_with_expanded_divs(
- __isl_keep isl_basic_map *bmap, int i, int j,
- struct isl_coalesce_info *info, __isl_keep isl_mat *div, int *exp)
- {
- enum isl_change change = isl_change_none;
- struct isl_coalesce_info info_local, *info_i;
- info_i = i >= 0 ? &info[i] : &info_local;
- init_status(info_i);
- bmap = isl_basic_map_copy(bmap);
- bmap = isl_basic_map_expand_divs(bmap, isl_mat_copy(div), exp);
- bmap = isl_basic_map_mark_final(bmap);
- if (!bmap)
- goto error;
- info_local.bmap = bmap;
- info_i->eq = eq_status_in(bmap, info[j].tab);
- if (bmap->n_eq && !info_i->eq)
- goto error;
- if (any_eq(info_i, STATUS_ERROR))
- goto error;
- if (any_eq(info_i, STATUS_SEPARATE))
- goto done;
- info_i->ineq = ineq_status_in(bmap, NULL, info[j].tab);
- if (bmap->n_ineq && !info_i->ineq)
- goto error;
- if (any_ineq(info_i, STATUS_ERROR))
- goto error;
- if (any_ineq(info_i, STATUS_SEPARATE))
- goto done;
- if (all(info_i->eq, 2 * bmap->n_eq, STATUS_VALID) &&
- all(info_i->ineq, bmap->n_ineq, STATUS_VALID)) {
- drop(&info[j]);
- change = isl_change_drop_second;
- }
- if (change == isl_change_none && i != -1)
- return coalesce_expand_tab_divs(bmap, i, j, info, div, exp);
- done:
- isl_basic_map_free(bmap);
- clear_status(info_i);
- return change;
- error:
- isl_basic_map_free(bmap);
- clear_status(info_i);
- return isl_change_error;
- }
- /* Check if the union of "bmap_i" and the basic map represented by info[j]
- * can be represented by a single basic map,
- * after aligning the divs of "bmap_i" to match those of info[j].
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- *
- * In particular, check if "bmap_i" contains the basic map represented by
- * info[j] after aligning the divs of "bmap_i" to those of info[j].
- * Note that this can only succeed if the number of divs of "bmap_i"
- * is smaller than (or equal to) the number of divs of info[j].
- *
- * We first check if the divs of "bmap_i" are all known and form a subset
- * of those of info[j].bmap. If so, we pass control over to
- * coalesce_with_expanded_divs.
- *
- * If "i" is not equal to -1, then "bmap" is equal to info[i].bmap.
- */
- static enum isl_change coalesce_after_aligning_divs(
- __isl_keep isl_basic_map *bmap_i, int i, int j,
- struct isl_coalesce_info *info)
- {
- isl_bool known;
- isl_mat *div_i, *div_j, *div;
- int *exp1 = NULL;
- int *exp2 = NULL;
- isl_ctx *ctx;
- enum isl_change change;
- known = isl_basic_map_divs_known(bmap_i);
- if (known < 0)
- return isl_change_error;
- if (!known)
- return isl_change_none;
- ctx = isl_basic_map_get_ctx(bmap_i);
- div_i = isl_basic_map_get_divs(bmap_i);
- div_j = isl_basic_map_get_divs(info[j].bmap);
- if (!div_i || !div_j)
- goto error;
- exp1 = isl_alloc_array(ctx, int, div_i->n_row);
- exp2 = isl_alloc_array(ctx, int, div_j->n_row);
- if ((div_i->n_row && !exp1) || (div_j->n_row && !exp2))
- goto error;
- div = isl_merge_divs(div_i, div_j, exp1, exp2);
- if (!div)
- goto error;
- if (div->n_row == div_j->n_row)
- change = coalesce_with_expanded_divs(bmap_i,
- i, j, info, div, exp1);
- else
- change = isl_change_none;
- isl_mat_free(div);
- isl_mat_free(div_i);
- isl_mat_free(div_j);
- free(exp2);
- free(exp1);
- return change;
- error:
- isl_mat_free(div_i);
- isl_mat_free(div_j);
- free(exp1);
- free(exp2);
- return isl_change_error;
- }
- /* Check if basic map "j" is a subset of basic map "i" after
- * exploiting the extra equalities of "j" to simplify the divs of "i".
- * If so, remove basic map "j" and return isl_change_drop_second.
- *
- * If "j" does not have any equalities or if they are the same
- * as those of "i", then we cannot exploit them to simplify the divs.
- * Similarly, if there are no divs in "i", then they cannot be simplified.
- * If, on the other hand, the affine hulls of "i" and "j" do not intersect,
- * then "j" cannot be a subset of "i".
- *
- * Otherwise, we intersect "i" with the affine hull of "j" and then
- * check if "j" is a subset of the result after aligning the divs.
- * If so, then "j" is definitely a subset of "i" and can be removed.
- * Note that if after intersection with the affine hull of "j".
- * "i" still has more divs than "j", then there is no way we can
- * align the divs of "i" to those of "j".
- */
- static enum isl_change coalesce_subset_with_equalities(int i, int j,
- struct isl_coalesce_info *info)
- {
- isl_basic_map *hull_i, *hull_j, *bmap_i;
- int equal, empty;
- enum isl_change change;
- if (info[j].bmap->n_eq == 0)
- return isl_change_none;
- if (info[i].bmap->n_div == 0)
- return isl_change_none;
- hull_i = isl_basic_map_copy(info[i].bmap);
- hull_i = isl_basic_map_plain_affine_hull(hull_i);
- hull_j = isl_basic_map_copy(info[j].bmap);
- hull_j = isl_basic_map_plain_affine_hull(hull_j);
- hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i));
- equal = isl_basic_map_plain_is_equal(hull_i, hull_j);
- empty = isl_basic_map_plain_is_empty(hull_j);
- isl_basic_map_free(hull_i);
- if (equal < 0 || equal || empty < 0 || empty) {
- isl_basic_map_free(hull_j);
- if (equal < 0 || empty < 0)
- return isl_change_error;
- return isl_change_none;
- }
- bmap_i = isl_basic_map_copy(info[i].bmap);
- bmap_i = isl_basic_map_intersect(bmap_i, hull_j);
- if (!bmap_i)
- return isl_change_error;
- if (bmap_i->n_div > info[j].bmap->n_div) {
- isl_basic_map_free(bmap_i);
- return isl_change_none;
- }
- change = coalesce_after_aligning_divs(bmap_i, -1, j, info);
- isl_basic_map_free(bmap_i);
- return change;
- }
- /* Check if the union of the basic maps represented by info[i] and info[j]
- * can be represented by a single basic map, by aligning or equating
- * their integer divisions.
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- *
- * Note that we only perform any test if the number of divs is different
- * in the two basic maps. In case the number of divs is the same,
- * we have already established that the divs are different
- * in the two basic maps.
- * In particular, if the number of divs of basic map i is smaller than
- * the number of divs of basic map j, then we check if j is a subset of i
- * and vice versa.
- */
- static enum isl_change coalesce_divs(int i, int j,
- struct isl_coalesce_info *info)
- {
- enum isl_change change = isl_change_none;
- if (info[i].bmap->n_div < info[j].bmap->n_div)
- change = coalesce_after_aligning_divs(info[i].bmap, i, j, info);
- if (change != isl_change_none)
- return change;
- if (info[j].bmap->n_div < info[i].bmap->n_div)
- change = coalesce_after_aligning_divs(info[j].bmap, j, i, info);
- if (change != isl_change_none)
- return invert_change(change);
- change = coalesce_subset_with_equalities(i, j, info);
- if (change != isl_change_none)
- return change;
- change = coalesce_subset_with_equalities(j, i, info);
- if (change != isl_change_none)
- return invert_change(change);
- return isl_change_none;
- }
- /* Does "bmap" involve any divs that themselves refer to divs?
- */
- static isl_bool has_nested_div(__isl_keep isl_basic_map *bmap)
- {
- int i;
- isl_size total;
- isl_size n_div;
- total = isl_basic_map_dim(bmap, isl_dim_all);
- n_div = isl_basic_map_dim(bmap, isl_dim_div);
- if (total < 0 || n_div < 0)
- return isl_bool_error;
- total -= n_div;
- for (i = 0; i < n_div; ++i)
- if (isl_seq_first_non_zero(bmap->div[i] + 2 + total,
- n_div) != -1)
- return isl_bool_true;
- return isl_bool_false;
- }
- /* Return a list of affine expressions, one for each integer division
- * in "bmap_i". For each integer division that also appears in "bmap_j",
- * the affine expression is set to NaN. The number of NaNs in the list
- * is equal to the number of integer divisions in "bmap_j".
- * For the other integer divisions of "bmap_i", the corresponding
- * element in the list is a purely affine expression equal to the integer
- * division in "hull".
- * If no such list can be constructed, then the number of elements
- * in the returned list is smaller than the number of integer divisions
- * in "bmap_i".
- * The integer division of "bmap_i" and "bmap_j" are assumed to be known and
- * not contain any nested divs.
- */
- static __isl_give isl_aff_list *set_up_substitutions(
- __isl_keep isl_basic_map *bmap_i, __isl_keep isl_basic_map *bmap_j,
- __isl_take isl_basic_map *hull)
- {
- isl_size n_div_i, n_div_j, total;
- isl_ctx *ctx;
- isl_local_space *ls;
- isl_basic_set *wrap_hull;
- isl_aff *aff_nan;
- isl_aff_list *list;
- int i, j;
- n_div_i = isl_basic_map_dim(bmap_i, isl_dim_div);
- n_div_j = isl_basic_map_dim(bmap_j, isl_dim_div);
- total = isl_basic_map_dim(bmap_i, isl_dim_all);
- if (!hull || n_div_i < 0 || n_div_j < 0 || total < 0)
- return NULL;
- ctx = isl_basic_map_get_ctx(hull);
- total -= n_div_i;
- ls = isl_basic_map_get_local_space(bmap_i);
- ls = isl_local_space_wrap(ls);
- wrap_hull = isl_basic_map_wrap(hull);
- aff_nan = isl_aff_nan_on_domain(isl_local_space_copy(ls));
- list = isl_aff_list_alloc(ctx, n_div_i);
- j = 0;
- for (i = 0; i < n_div_i; ++i) {
- isl_aff *aff;
- isl_size n_div;
- if (j < n_div_j &&
- isl_basic_map_equal_div_expr_part(bmap_i, i, bmap_j, j,
- 0, 2 + total)) {
- ++j;
- list = isl_aff_list_add(list, isl_aff_copy(aff_nan));
- continue;
- }
- if (n_div_i - i <= n_div_j - j)
- break;
- aff = isl_local_space_get_div(ls, i);
- aff = isl_aff_substitute_equalities(aff,
- isl_basic_set_copy(wrap_hull));
- aff = isl_aff_floor(aff);
- n_div = isl_aff_dim(aff, isl_dim_div);
- if (n_div < 0)
- goto error;
- if (n_div != 0) {
- isl_aff_free(aff);
- break;
- }
- list = isl_aff_list_add(list, aff);
- }
- isl_aff_free(aff_nan);
- isl_local_space_free(ls);
- isl_basic_set_free(wrap_hull);
- return list;
- error:
- isl_aff_free(aff_nan);
- isl_local_space_free(ls);
- isl_basic_set_free(wrap_hull);
- isl_aff_list_free(list);
- return NULL;
- }
- /* Add variables to info->bmap and info->tab corresponding to the elements
- * in "list" that are not set to NaN.
- * "extra_var" is the number of these elements.
- * "dim" is the offset in the variables of "tab" where we should
- * start considering the elements in "list".
- * When this function returns, the total number of variables in "tab"
- * is equal to "dim" plus the number of elements in "list".
- *
- * The newly added existentially quantified variables are not given
- * an explicit representation because the corresponding div constraints
- * do not appear in info->bmap. These constraints are not added
- * to info->bmap because for internal consistency, they would need to
- * be added to info->tab as well, where they could combine with the equality
- * that is added later to result in constraints that do not hold
- * in the original input.
- */
- static isl_stat add_sub_vars(struct isl_coalesce_info *info,
- __isl_keep isl_aff_list *list, int dim, int extra_var)
- {
- int i, j, d;
- isl_size n;
- info->bmap = isl_basic_map_cow(info->bmap);
- info->bmap = isl_basic_map_extend(info->bmap, extra_var, 0, 0);
- n = isl_aff_list_n_aff(list);
- if (!info->bmap || n < 0)
- return isl_stat_error;
- for (i = 0; i < n; ++i) {
- int is_nan;
- isl_aff *aff;
- aff = isl_aff_list_get_aff(list, i);
- is_nan = isl_aff_is_nan(aff);
- isl_aff_free(aff);
- if (is_nan < 0)
- return isl_stat_error;
- if (is_nan)
- continue;
- if (isl_tab_insert_var(info->tab, dim + i) < 0)
- return isl_stat_error;
- d = isl_basic_map_alloc_div(info->bmap);
- if (d < 0)
- return isl_stat_error;
- info->bmap = isl_basic_map_mark_div_unknown(info->bmap, d);
- for (j = d; j > i; --j)
- info->bmap = isl_basic_map_swap_div(info->bmap,
- j - 1, j);
- if (!info->bmap)
- return isl_stat_error;
- }
- return isl_stat_ok;
- }
- /* For each element in "list" that is not set to NaN, fix the corresponding
- * variable in "tab" to the purely affine expression defined by the element.
- * "dim" is the offset in the variables of "tab" where we should
- * start considering the elements in "list".
- *
- * This function assumes that a sufficient number of rows and
- * elements in the constraint array are available in the tableau.
- */
- static isl_stat add_sub_equalities(struct isl_tab *tab,
- __isl_keep isl_aff_list *list, int dim)
- {
- int i;
- isl_size n;
- isl_ctx *ctx;
- isl_vec *sub;
- isl_aff *aff;
- n = isl_aff_list_n_aff(list);
- if (n < 0)
- return isl_stat_error;
- ctx = isl_tab_get_ctx(tab);
- sub = isl_vec_alloc(ctx, 1 + dim + n);
- if (!sub)
- return isl_stat_error;
- isl_seq_clr(sub->el + 1 + dim, n);
- for (i = 0; i < n; ++i) {
- aff = isl_aff_list_get_aff(list, i);
- if (!aff)
- goto error;
- if (isl_aff_is_nan(aff)) {
- isl_aff_free(aff);
- continue;
- }
- isl_seq_cpy(sub->el, aff->v->el + 1, 1 + dim);
- isl_int_neg(sub->el[1 + dim + i], aff->v->el[0]);
- if (isl_tab_add_eq(tab, sub->el) < 0)
- goto error;
- isl_int_set_si(sub->el[1 + dim + i], 0);
- isl_aff_free(aff);
- }
- isl_vec_free(sub);
- return isl_stat_ok;
- error:
- isl_aff_free(aff);
- isl_vec_free(sub);
- return isl_stat_error;
- }
- /* Add variables to info->tab and info->bmap corresponding to the elements
- * in "list" that are not set to NaN. The value of the added variable
- * in info->tab is fixed to the purely affine expression defined by the element.
- * "dim" is the offset in the variables of info->tab where we should
- * start considering the elements in "list".
- * When this function returns, the total number of variables in info->tab
- * is equal to "dim" plus the number of elements in "list".
- */
- static isl_stat add_subs(struct isl_coalesce_info *info,
- __isl_keep isl_aff_list *list, int dim)
- {
- int extra_var;
- isl_size n;
- n = isl_aff_list_n_aff(list);
- if (n < 0)
- return isl_stat_error;
- extra_var = n - (info->tab->n_var - dim);
- if (isl_tab_extend_vars(info->tab, extra_var) < 0)
- return isl_stat_error;
- if (isl_tab_extend_cons(info->tab, 2 * extra_var) < 0)
- return isl_stat_error;
- if (add_sub_vars(info, list, dim, extra_var) < 0)
- return isl_stat_error;
- return add_sub_equalities(info->tab, list, dim);
- }
- /* Coalesce basic map "j" into basic map "i" after adding the extra integer
- * divisions in "i" but not in "j" to basic map "j", with values
- * specified by "list". The total number of elements in "list"
- * is equal to the number of integer divisions in "i", while the number
- * of NaN elements in the list is equal to the number of integer divisions
- * in "j".
- *
- * If no coalescing can be performed, then we need to revert basic map "j"
- * to its original state. We do the same if basic map "i" gets dropped
- * during the coalescing, even though this should not happen in practice
- * since we have already checked for "j" being a subset of "i"
- * before we reach this stage.
- */
- static enum isl_change coalesce_with_subs(int i, int j,
- struct isl_coalesce_info *info, __isl_keep isl_aff_list *list)
- {
- isl_basic_map *bmap_j;
- struct isl_tab_undo *snap;
- isl_size dim, n_div;
- enum isl_change change;
- bmap_j = isl_basic_map_copy(info[j].bmap);
- snap = isl_tab_snap(info[j].tab);
- dim = isl_basic_map_dim(bmap_j, isl_dim_all);
- n_div = isl_basic_map_dim(bmap_j, isl_dim_div);
- if (dim < 0 || n_div < 0)
- goto error;
- dim -= n_div;
- if (add_subs(&info[j], list, dim) < 0)
- goto error;
- change = coalesce_local_pair(i, j, info);
- if (change != isl_change_none && change != isl_change_drop_first) {
- isl_basic_map_free(bmap_j);
- } else {
- isl_basic_map_free(info[j].bmap);
- info[j].bmap = bmap_j;
- if (isl_tab_rollback(info[j].tab, snap) < 0)
- return isl_change_error;
- }
- return change;
- error:
- isl_basic_map_free(bmap_j);
- return isl_change_error;
- }
- /* Check if we can coalesce basic map "j" into basic map "i" after copying
- * those extra integer divisions in "i" that can be simplified away
- * using the extra equalities in "j".
- * All divs are assumed to be known and not contain any nested divs.
- *
- * We first check if there are any extra equalities in "j" that we
- * can exploit. Then we check if every integer division in "i"
- * either already appears in "j" or can be simplified using the
- * extra equalities to a purely affine expression.
- * If these tests succeed, then we try to coalesce the two basic maps
- * by introducing extra dimensions in "j" corresponding to
- * the extra integer divisions "i" fixed to the corresponding
- * purely affine expression.
- */
- static enum isl_change check_coalesce_into_eq(int i, int j,
- struct isl_coalesce_info *info)
- {
- isl_size n_div_i, n_div_j, n;
- isl_basic_map *hull_i, *hull_j;
- isl_bool equal, empty;
- isl_aff_list *list;
- enum isl_change change;
- n_div_i = isl_basic_map_dim(info[i].bmap, isl_dim_div);
- n_div_j = isl_basic_map_dim(info[j].bmap, isl_dim_div);
- if (n_div_i < 0 || n_div_j < 0)
- return isl_change_error;
- if (n_div_i <= n_div_j)
- return isl_change_none;
- if (info[j].bmap->n_eq == 0)
- return isl_change_none;
- hull_i = isl_basic_map_copy(info[i].bmap);
- hull_i = isl_basic_map_plain_affine_hull(hull_i);
- hull_j = isl_basic_map_copy(info[j].bmap);
- hull_j = isl_basic_map_plain_affine_hull(hull_j);
- hull_j = isl_basic_map_intersect(hull_j, isl_basic_map_copy(hull_i));
- equal = isl_basic_map_plain_is_equal(hull_i, hull_j);
- empty = isl_basic_map_plain_is_empty(hull_j);
- isl_basic_map_free(hull_i);
- if (equal < 0 || empty < 0)
- goto error;
- if (equal || empty) {
- isl_basic_map_free(hull_j);
- return isl_change_none;
- }
- list = set_up_substitutions(info[i].bmap, info[j].bmap, hull_j);
- if (!list)
- return isl_change_error;
- n = isl_aff_list_n_aff(list);
- if (n < 0)
- change = isl_change_error;
- else if (n < n_div_i)
- change = isl_change_none;
- else
- change = coalesce_with_subs(i, j, info, list);
- isl_aff_list_free(list);
- return change;
- error:
- isl_basic_map_free(hull_j);
- return isl_change_error;
- }
- /* Check if we can coalesce basic maps "i" and "j" after copying
- * those extra integer divisions in one of the basic maps that can
- * be simplified away using the extra equalities in the other basic map.
- * We require all divs to be known in both basic maps.
- * Furthermore, to simplify the comparison of div expressions,
- * we do not allow any nested integer divisions.
- */
- static enum isl_change check_coalesce_eq(int i, int j,
- struct isl_coalesce_info *info)
- {
- isl_bool known, nested;
- enum isl_change change;
- known = isl_basic_map_divs_known(info[i].bmap);
- if (known < 0 || !known)
- return known < 0 ? isl_change_error : isl_change_none;
- known = isl_basic_map_divs_known(info[j].bmap);
- if (known < 0 || !known)
- return known < 0 ? isl_change_error : isl_change_none;
- nested = has_nested_div(info[i].bmap);
- if (nested < 0 || nested)
- return nested < 0 ? isl_change_error : isl_change_none;
- nested = has_nested_div(info[j].bmap);
- if (nested < 0 || nested)
- return nested < 0 ? isl_change_error : isl_change_none;
- change = check_coalesce_into_eq(i, j, info);
- if (change != isl_change_none)
- return change;
- change = check_coalesce_into_eq(j, i, info);
- if (change != isl_change_none)
- return invert_change(change);
- return isl_change_none;
- }
- /* Check if the union of the given pair of basic maps
- * can be represented by a single basic map.
- * If so, replace the pair by the single basic map and return
- * isl_change_drop_first, isl_change_drop_second or isl_change_fuse.
- * Otherwise, return isl_change_none.
- *
- * We first check if the two basic maps live in the same local space,
- * after aligning the divs that differ by only an integer constant.
- * If so, we do the complete check. Otherwise, we check if they have
- * the same number of integer divisions and can be coalesced, if one is
- * an obvious subset of the other or if the extra integer divisions
- * of one basic map can be simplified away using the extra equalities
- * of the other basic map.
- *
- * Note that trying to coalesce pairs of disjuncts with the same
- * number, but different local variables may drop the explicit
- * representation of some of these local variables.
- * This operation is therefore not performed when
- * the "coalesce_preserve_locals" option is set.
- */
- static enum isl_change coalesce_pair(int i, int j,
- struct isl_coalesce_info *info)
- {
- int preserve;
- isl_bool same;
- enum isl_change change;
- isl_ctx *ctx;
- if (harmonize_divs(&info[i], &info[j]) < 0)
- return isl_change_error;
- same = same_divs(info[i].bmap, info[j].bmap);
- if (same < 0)
- return isl_change_error;
- if (same)
- return coalesce_local_pair(i, j, info);
- ctx = isl_basic_map_get_ctx(info[i].bmap);
- preserve = isl_options_get_coalesce_preserve_locals(ctx);
- if (!preserve && info[i].bmap->n_div == info[j].bmap->n_div) {
- change = coalesce_local_pair(i, j, info);
- if (change != isl_change_none)
- return change;
- }
- change = coalesce_divs(i, j, info);
- if (change != isl_change_none)
- return change;
- return check_coalesce_eq(i, j, info);
- }
- /* Return the maximum of "a" and "b".
- */
- static int isl_max(int a, int b)
- {
- return a > b ? a : b;
- }
- /* Pairwise coalesce the basic maps in the range [start1, end1[ of "info"
- * with those in the range [start2, end2[, skipping basic maps
- * that have been removed (either before or within this function).
- *
- * For each basic map i in the first range, we check if it can be coalesced
- * with respect to any previously considered basic map j in the second range.
- * If i gets dropped (because it was a subset of some j), then
- * we can move on to the next basic map.
- * If j gets dropped, we need to continue checking against the other
- * previously considered basic maps.
- * If the two basic maps got fused, then we recheck the fused basic map
- * against the previously considered basic maps, starting at i + 1
- * (even if start2 is greater than i + 1).
- */
- static int coalesce_range(isl_ctx *ctx, struct isl_coalesce_info *info,
- int start1, int end1, int start2, int end2)
- {
- int i, j;
- for (i = end1 - 1; i >= start1; --i) {
- if (info[i].removed)
- continue;
- for (j = isl_max(i + 1, start2); j < end2; ++j) {
- enum isl_change changed;
- if (info[j].removed)
- continue;
- if (info[i].removed)
- isl_die(ctx, isl_error_internal,
- "basic map unexpectedly removed",
- return -1);
- changed = coalesce_pair(i, j, info);
- switch (changed) {
- case isl_change_error:
- return -1;
- case isl_change_none:
- case isl_change_drop_second:
- continue;
- case isl_change_drop_first:
- j = end2;
- break;
- case isl_change_fuse:
- j = i;
- break;
- }
- }
- }
- return 0;
- }
- /* Pairwise coalesce the basic maps described by the "n" elements of "info".
- *
- * We consider groups of basic maps that live in the same apparent
- * affine hull and we first coalesce within such a group before we
- * coalesce the elements in the group with elements of previously
- * considered groups. If a fuse happens during the second phase,
- * then we also reconsider the elements within the group.
- */
- static int coalesce(isl_ctx *ctx, int n, struct isl_coalesce_info *info)
- {
- int start, end;
- for (end = n; end > 0; end = start) {
- start = end - 1;
- while (start >= 1 &&
- info[start - 1].hull_hash == info[start].hull_hash)
- start--;
- if (coalesce_range(ctx, info, start, end, start, end) < 0)
- return -1;
- if (coalesce_range(ctx, info, start, end, end, n) < 0)
- return -1;
- }
- return 0;
- }
- /* Update the basic maps in "map" based on the information in "info".
- * In particular, remove the basic maps that have been marked removed and
- * update the others based on the information in the corresponding tableau.
- * Since we detected implicit equalities without calling
- * isl_basic_map_gauss, we need to do it now.
- * Also call isl_basic_map_simplify if we may have lost the definition
- * of one or more integer divisions.
- * If a basic map is still equal to the one from which the corresponding "info"
- * entry was created, then redundant constraint and
- * implicit equality constraint detection have been performed
- * on the corresponding tableau and the basic map can be marked as such.
- */
- static __isl_give isl_map *update_basic_maps(__isl_take isl_map *map,
- int n, struct isl_coalesce_info *info)
- {
- int i;
- if (!map)
- return NULL;
- for (i = n - 1; i >= 0; --i) {
- if (info[i].removed) {
- isl_basic_map_free(map->p[i]);
- if (i != map->n - 1)
- map->p[i] = map->p[map->n - 1];
- map->n--;
- continue;
- }
- info[i].bmap = isl_basic_map_update_from_tab(info[i].bmap,
- info[i].tab);
- info[i].bmap = isl_basic_map_gauss(info[i].bmap, NULL);
- if (info[i].simplify)
- info[i].bmap = isl_basic_map_simplify(info[i].bmap);
- info[i].bmap = isl_basic_map_finalize(info[i].bmap);
- if (!info[i].bmap)
- return isl_map_free(map);
- if (!info[i].modified) {
- ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT);
- ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT);
- }
- isl_basic_map_free(map->p[i]);
- map->p[i] = info[i].bmap;
- info[i].bmap = NULL;
- }
- return map;
- }
- /* For each pair of basic maps in the map, check if the union of the two
- * can be represented by a single basic map.
- * If so, replace the pair by the single basic map and start over.
- *
- * We factor out any (hidden) common factor from the constraint
- * coefficients to improve the detection of adjacent constraints.
- * Note that this function does not call isl_basic_map_gauss,
- * but it does make sure that only a single copy of the basic map
- * is affected. This means that isl_basic_map_gauss may have
- * to be called at the end of the computation (in update_basic_maps)
- * on this single copy to ensure that
- * the basic maps are not left in an unexpected state.
- *
- * Since we are constructing the tableaus of the basic maps anyway,
- * we exploit them to detect implicit equalities and redundant constraints.
- * This also helps the coalescing as it can ignore the redundant constraints.
- * In order to avoid confusion, we make all implicit equalities explicit
- * in the basic maps. If the basic map only has a single reference
- * (this happens in particular if it was modified by
- * isl_basic_map_reduce_coefficients), then isl_basic_map_gauss
- * does not get called on the result. The call to
- * isl_basic_map_gauss in update_basic_maps resolves this as well.
- * For each basic map, we also compute the hash of the apparent affine hull
- * for use in coalesce.
- */
- __isl_give isl_map *isl_map_coalesce(__isl_take isl_map *map)
- {
- int i;
- unsigned n;
- isl_ctx *ctx;
- struct isl_coalesce_info *info = NULL;
- map = isl_map_remove_empty_parts(map);
- if (!map)
- return NULL;
- if (map->n <= 1)
- return map;
- ctx = isl_map_get_ctx(map);
- map = isl_map_sort_divs(map);
- map = isl_map_cow(map);
- if (!map)
- return NULL;
- n = map->n;
- info = isl_calloc_array(map->ctx, struct isl_coalesce_info, n);
- if (!info)
- goto error;
- for (i = 0; i < map->n; ++i) {
- map->p[i] = isl_basic_map_reduce_coefficients(map->p[i]);
- if (!map->p[i])
- goto error;
- info[i].bmap = isl_basic_map_copy(map->p[i]);
- info[i].tab = isl_tab_from_basic_map(info[i].bmap, 0);
- if (!info[i].tab)
- goto error;
- if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_IMPLICIT))
- if (isl_tab_detect_implicit_equalities(info[i].tab) < 0)
- goto error;
- info[i].bmap = isl_tab_make_equalities_explicit(info[i].tab,
- info[i].bmap);
- if (!info[i].bmap)
- goto error;
- if (!ISL_F_ISSET(info[i].bmap, ISL_BASIC_MAP_NO_REDUNDANT))
- if (isl_tab_detect_redundant(info[i].tab) < 0)
- goto error;
- if (coalesce_info_set_hull_hash(&info[i]) < 0)
- goto error;
- }
- for (i = map->n - 1; i >= 0; --i)
- if (info[i].tab->empty)
- drop(&info[i]);
- if (coalesce(ctx, n, info) < 0)
- goto error;
- map = update_basic_maps(map, n, info);
- clear_coalesce_info(n, info);
- return map;
- error:
- clear_coalesce_info(n, info);
- isl_map_free(map);
- return NULL;
- }
- /* For each pair of basic sets in the set, check if the union of the two
- * can be represented by a single basic set.
- * If so, replace the pair by the single basic set and start over.
- */
- __isl_give isl_set *isl_set_coalesce(__isl_take isl_set *set)
- {
- return set_from_map(isl_map_coalesce(set_to_map(set)));
- }
|