3 Star 0 Fork 1

Gitee 极速下载/isl

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://repo.or.cz/isl.git
克隆/下载
isl_schedule_tree.c 78.08 KB
一键复制 编辑 原始数据 按行查看 历史
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906
/*
* Copyright 2013-2014 Ecole Normale Superieure
* Copyright 2014 INRIA Rocquencourt
* Copyright 2016 INRIA Paris
*
* Use of this software is governed by the MIT license
*
* Written by Sven Verdoolaege,
* 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
*/
#include <isl/id.h>
#include <isl/val.h>
#include <isl/space.h>
#include <isl/map.h>
#include <isl_schedule_band.h>
#include <isl_schedule_private.h>
#undef EL
#define EL isl_schedule_tree
#include <isl_list_templ.h>
#undef EL_BASE
#define EL_BASE schedule_tree
#include <isl_list_templ.c>
/* Is "tree" the leaf of a schedule tree?
*/
int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree)
{
return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf;
}
/* Create a new schedule tree of type "type".
* The caller is responsible for filling in the type specific fields and
* the children.
*
* By default, the single node tree does not have any anchored nodes.
* The caller is responsible for updating the anchored field if needed.
*/
static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx,
enum isl_schedule_node_type type)
{
isl_schedule_tree *tree;
if (type == isl_schedule_node_error)
return NULL;
tree = isl_calloc_type(ctx, isl_schedule_tree);
if (!tree)
return NULL;
tree->ref = 1;
tree->ctx = ctx;
isl_ctx_ref(ctx);
tree->type = type;
tree->anchored = 0;
return tree;
}
/* Return a fresh copy of "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_dup(
__isl_keep isl_schedule_tree *tree)
{
isl_ctx *ctx;
isl_schedule_tree *dup;
if (!tree)
return NULL;
ctx = isl_schedule_tree_get_ctx(tree);
dup = isl_schedule_tree_alloc(ctx, tree->type);
if (!dup)
return NULL;
switch (tree->type) {
case isl_schedule_node_error:
isl_die(ctx, isl_error_internal,
"allocation should have failed",
return isl_schedule_tree_free(dup));
case isl_schedule_node_band:
dup->band = isl_schedule_band_copy(tree->band);
if (!dup->band)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_context:
dup->context = isl_set_copy(tree->context);
if (!dup->context)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_domain:
dup->domain = isl_union_set_copy(tree->domain);
if (!dup->domain)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_expansion:
dup->contraction =
isl_union_pw_multi_aff_copy(tree->contraction);
dup->expansion = isl_union_map_copy(tree->expansion);
if (!dup->contraction || !dup->expansion)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_extension:
dup->extension = isl_union_map_copy(tree->extension);
if (!dup->extension)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_filter:
dup->filter = isl_union_set_copy(tree->filter);
if (!dup->filter)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_guard:
dup->guard = isl_set_copy(tree->guard);
if (!dup->guard)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_mark:
dup->mark = isl_id_copy(tree->mark);
if (!dup->mark)
return isl_schedule_tree_free(dup);
break;
case isl_schedule_node_leaf:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
break;
}
if (tree->children) {
dup->children = isl_schedule_tree_list_copy(tree->children);
if (!dup->children)
return isl_schedule_tree_free(dup);
}
dup->anchored = tree->anchored;
return dup;
}
/* Return an isl_schedule_tree that is equal to "tree" and that has only
* a single reference.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_cow(
__isl_take isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->ref == 1)
return tree;
tree->ref--;
return isl_schedule_tree_dup(tree);
}
/* Return a new reference to "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_copy(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
tree->ref++;
return tree;
}
/* Free "tree" and return NULL.
*/
__isl_null isl_schedule_tree *isl_schedule_tree_free(
__isl_take isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (--tree->ref > 0)
return NULL;
switch (tree->type) {
case isl_schedule_node_band:
isl_schedule_band_free(tree->band);
break;
case isl_schedule_node_context:
isl_set_free(tree->context);
break;
case isl_schedule_node_domain:
isl_union_set_free(tree->domain);
break;
case isl_schedule_node_expansion:
isl_union_pw_multi_aff_free(tree->contraction);
isl_union_map_free(tree->expansion);
break;
case isl_schedule_node_extension:
isl_union_map_free(tree->extension);
break;
case isl_schedule_node_filter:
isl_union_set_free(tree->filter);
break;
case isl_schedule_node_guard:
isl_set_free(tree->guard);
break;
case isl_schedule_node_mark:
isl_id_free(tree->mark);
break;
case isl_schedule_node_sequence:
case isl_schedule_node_set:
case isl_schedule_node_error:
case isl_schedule_node_leaf:
break;
}
isl_schedule_tree_list_free(tree->children);
isl_ctx_deref(tree->ctx);
free(tree);
return NULL;
}
/* Create and return a new leaf schedule tree.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
{
return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
}
/* Create a new band schedule tree referring to "band"
* with no children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_band(
__isl_take isl_schedule_band *band)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!band)
return NULL;
ctx = isl_schedule_band_get_ctx(band);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
if (!tree)
goto error;
tree->band = band;
tree->anchored = isl_schedule_band_is_anchored(band);
return tree;
error:
isl_schedule_band_free(band);
return NULL;
}
/* Create a new context schedule tree with the given context and no children.
* Since the context references the outer schedule dimension,
* the tree is anchored.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_context(
__isl_take isl_set *context)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!context)
return NULL;
ctx = isl_set_get_ctx(context);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
if (!tree)
goto error;
tree->context = context;
tree->anchored = 1;
return tree;
error:
isl_set_free(context);
return NULL;
}
/* Create a new domain schedule tree with the given domain and no children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
__isl_take isl_union_set *domain)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!domain)
return NULL;
ctx = isl_union_set_get_ctx(domain);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
if (!tree)
goto error;
tree->domain = domain;
return tree;
error:
isl_union_set_free(domain);
return NULL;
}
/* Create a new expansion schedule tree with the given contraction and
* expansion and no children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
__isl_take isl_union_pw_multi_aff *contraction,
__isl_take isl_union_map *expansion)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!contraction || !expansion)
goto error;
ctx = isl_union_map_get_ctx(expansion);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
if (!tree)
goto error;
tree->contraction = contraction;
tree->expansion = expansion;
return tree;
error:
isl_union_pw_multi_aff_free(contraction);
isl_union_map_free(expansion);
return NULL;
}
/* Create a new extension schedule tree with the given extension and
* no children.
* Since the domain of the extension refers to the outer schedule dimension,
* the tree is anchored.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
__isl_take isl_union_map *extension)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!extension)
return NULL;
ctx = isl_union_map_get_ctx(extension);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
if (!tree)
goto error;
tree->extension = extension;
tree->anchored = 1;
return tree;
error:
isl_union_map_free(extension);
return NULL;
}
/* Create a new filter schedule tree with the given filter and no children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
__isl_take isl_union_set *filter)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!filter)
return NULL;
ctx = isl_union_set_get_ctx(filter);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
if (!tree)
goto error;
tree->filter = filter;
return tree;
error:
isl_union_set_free(filter);
return NULL;
}
/* Create a new guard schedule tree with the given guard and no children.
* Since the guard references the outer schedule dimension,
* the tree is anchored.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
__isl_take isl_set *guard)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!guard)
return NULL;
ctx = isl_set_get_ctx(guard);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
if (!tree)
goto error;
tree->guard = guard;
tree->anchored = 1;
return tree;
error:
isl_set_free(guard);
return NULL;
}
/* Create a new mark schedule tree with the given mark identifier and
* no children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
__isl_take isl_id *mark)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!mark)
return NULL;
ctx = isl_id_get_ctx(mark);
tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
if (!tree)
goto error;
tree->mark = mark;
return tree;
error:
isl_id_free(mark);
return NULL;
}
/* Does "tree" have any node that depends on its position
* in the complete schedule tree?
*/
isl_bool isl_schedule_tree_is_subtree_anchored(
__isl_keep isl_schedule_tree *tree)
{
return tree ? isl_bool_ok(tree->anchored) : isl_bool_error;
}
/* Does the root node of "tree" depend on its position in the complete
* schedule tree?
* Band nodes may be anchored depending on the associated AST build options.
* Context, extension and guard nodes are always anchored.
*/
int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return -1;
switch (isl_schedule_tree_get_type(tree)) {
case isl_schedule_node_error:
return -1;
case isl_schedule_node_band:
return isl_schedule_band_is_anchored(tree->band);
case isl_schedule_node_context:
case isl_schedule_node_extension:
case isl_schedule_node_guard:
return 1;
case isl_schedule_node_domain:
case isl_schedule_node_expansion:
case isl_schedule_node_filter:
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
return 0;
}
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"unhandled case", return -1);
}
/* Update the anchored field of "tree" based on whether the root node
* itself in anchored and the anchored fields of the children.
*
* This function should be called whenever the children of a tree node
* are changed or the anchoredness of the tree root itself changes.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
__isl_take isl_schedule_tree *tree)
{
int i;
isl_size n;
int anchored;
anchored = isl_schedule_tree_is_anchored(tree);
n = isl_schedule_tree_n_children(tree);
if (anchored < 0 || n < 0)
return isl_schedule_tree_free(tree);
for (i = 0; !anchored && i < n; ++i) {
isl_schedule_tree *child;
child = isl_schedule_tree_get_child(tree, i);
if (!child)
return isl_schedule_tree_free(tree);
anchored = child->anchored;
isl_schedule_tree_free(child);
}
if (anchored == tree->anchored)
return tree;
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
tree->anchored = anchored;
return tree;
}
/* Create a new tree of the given type (isl_schedule_node_sequence or
* isl_schedule_node_set) with the given children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_children(
enum isl_schedule_node_type type,
__isl_take isl_schedule_tree_list *list)
{
isl_ctx *ctx;
isl_schedule_tree *tree;
if (!list)
return NULL;
ctx = isl_schedule_tree_list_get_ctx(list);
tree = isl_schedule_tree_alloc(ctx, type);
if (!tree)
goto error;
tree->children = list;
tree = isl_schedule_tree_update_anchored(tree);
return tree;
error:
isl_schedule_tree_list_free(list);
return NULL;
}
/* Construct a tree with a root node of type "type" and as children
* "tree1" and "tree2".
* If the root of one (or both) of the input trees is itself of type "type",
* then the tree is replaced by its children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
__isl_take isl_schedule_tree *tree2)
{
isl_ctx *ctx;
isl_schedule_tree_list *list;
if (!tree1 || !tree2)
goto error;
ctx = isl_schedule_tree_get_ctx(tree1);
if (isl_schedule_tree_get_type(tree1) == type) {
list = isl_schedule_tree_list_copy(tree1->children);
isl_schedule_tree_free(tree1);
} else {
list = isl_schedule_tree_list_alloc(ctx, 2);
list = isl_schedule_tree_list_add(list, tree1);
}
if (isl_schedule_tree_get_type(tree2) == type) {
isl_schedule_tree_list *children;
children = isl_schedule_tree_list_copy(tree2->children);
list = isl_schedule_tree_list_concat(list, children);
isl_schedule_tree_free(tree2);
} else {
list = isl_schedule_tree_list_add(list, tree2);
}
return isl_schedule_tree_from_children(type, list);
error:
isl_schedule_tree_free(tree1);
isl_schedule_tree_free(tree2);
return NULL;
}
/* Construct a tree with a sequence root node and as children
* "tree1" and "tree2".
* If the root of one (or both) of the input trees is itself a sequence,
* then the tree is replaced by its children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
__isl_take isl_schedule_tree *tree1,
__isl_take isl_schedule_tree *tree2)
{
return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
tree1, tree2);
}
/* Construct a tree with a set root node and as children
* "tree1" and "tree2".
* If the root of one (or both) of the input trees is itself a set,
* then the tree is replaced by its children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_set_pair(
__isl_take isl_schedule_tree *tree1,
__isl_take isl_schedule_tree *tree2)
{
return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2);
}
/* Return the isl_ctx to which "tree" belongs.
*/
isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
{
return tree ? tree->ctx : NULL;
}
/* Return the type of the root of the tree or isl_schedule_node_error
* on error.
*/
enum isl_schedule_node_type isl_schedule_tree_get_type(
__isl_keep isl_schedule_tree *tree)
{
return tree ? tree->type : isl_schedule_node_error;
}
/* Are "tree1" and "tree2" obviously equal to each other?
*/
isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
__isl_keep isl_schedule_tree *tree2)
{
isl_bool equal;
int i;
isl_size n1, n2;
if (!tree1 || !tree2)
return isl_bool_error;
if (tree1 == tree2)
return isl_bool_true;
if (tree1->type != tree2->type)
return isl_bool_false;
switch (tree1->type) {
case isl_schedule_node_band:
equal = isl_schedule_band_plain_is_equal(tree1->band,
tree2->band);
break;
case isl_schedule_node_context:
equal = isl_set_is_equal(tree1->context, tree2->context);
break;
case isl_schedule_node_domain:
equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
break;
case isl_schedule_node_expansion:
equal = isl_union_map_is_equal(tree1->expansion,
tree2->expansion);
if (equal >= 0 && equal)
equal = isl_union_pw_multi_aff_plain_is_equal(
tree1->contraction, tree2->contraction);
break;
case isl_schedule_node_extension:
equal = isl_union_map_is_equal(tree1->extension,
tree2->extension);
break;
case isl_schedule_node_filter:
equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
break;
case isl_schedule_node_guard:
equal = isl_set_is_equal(tree1->guard, tree2->guard);
break;
case isl_schedule_node_mark:
equal = isl_bool_ok(tree1->mark == tree2->mark);
break;
case isl_schedule_node_leaf:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
equal = isl_bool_true;
break;
case isl_schedule_node_error:
equal = isl_bool_error;
break;
}
if (equal < 0 || !equal)
return equal;
n1 = isl_schedule_tree_n_children(tree1);
n2 = isl_schedule_tree_n_children(tree2);
if (n1 < 0 || n2 < 0)
return isl_bool_error;
if (n1 != n2)
return isl_bool_false;
for (i = 0; i < n1; ++i) {
isl_schedule_tree *child1, *child2;
child1 = isl_schedule_tree_get_child(tree1, i);
child2 = isl_schedule_tree_get_child(tree2, i);
equal = isl_schedule_tree_plain_is_equal(child1, child2);
isl_schedule_tree_free(child1);
isl_schedule_tree_free(child2);
if (equal < 0 || !equal)
return equal;
}
return isl_bool_true;
}
/* Does "tree" have any children, other than an implicit leaf.
*/
int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return -1;
return tree->children != NULL;
}
/* Return the number of children of "tree", excluding implicit leaves.
* The "children" field is NULL if there are
* no children (except for the implicit leaves).
*/
isl_size isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return isl_size_error;
if (!tree->children)
return 0;
return isl_schedule_tree_list_n_schedule_tree(tree->children);
}
/* Return a copy of the (explicit) child at position "pos" of "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_get_child(
__isl_keep isl_schedule_tree *tree, int pos)
{
if (!tree)
return NULL;
if (!tree->children)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"schedule tree has no explicit children", return NULL);
return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
}
/* Return a copy of the (explicit) child at position "pos" of "tree" and
* free "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_child(
__isl_take isl_schedule_tree *tree, int pos)
{
isl_schedule_tree *child;
child = isl_schedule_tree_get_child(tree, pos);
isl_schedule_tree_free(tree);
return child;
}
/* Remove all (explicit) children from "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
__isl_take isl_schedule_tree *tree)
{
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
tree->children = isl_schedule_tree_list_free(tree->children);
return tree;
}
/* Remove the child at position "pos" from the children of "tree".
* If there was only one child to begin with, then remove all children.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
__isl_take isl_schedule_tree *tree, int pos)
{
isl_size n;
tree = isl_schedule_tree_cow(tree);
n = isl_schedule_tree_n_children(tree);
if (n < 0)
return isl_schedule_tree_free(tree);
if (n == 0)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"tree does not have any explicit children",
return isl_schedule_tree_free(tree));
if (pos < 0 || pos >= n)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"position out of bounds",
return isl_schedule_tree_free(tree));
if (n == 1)
return isl_schedule_tree_reset_children(tree);
tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
if (!tree->children)
return isl_schedule_tree_free(tree);
return tree;
}
/* Replace the child at position "pos" of "tree" by "child".
*
* If the new child is a leaf, then it is not explicitly
* recorded in the list of children. Instead, the list of children
* (which is assumed to have only one element) is removed.
* Note that the children of set and sequence nodes are always
* filters, so they cannot be replaced by empty trees.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
__isl_take isl_schedule_tree *tree, int pos,
__isl_take isl_schedule_tree *child)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !child)
goto error;
if (isl_schedule_tree_is_leaf(child)) {
isl_size n;
isl_schedule_tree_free(child);
if (!tree->children && pos == 0)
return tree;
n = isl_schedule_tree_n_children(tree);
if (n < 0)
return isl_schedule_tree_free(tree);
if (n != 1)
isl_die(isl_schedule_tree_get_ctx(tree),
isl_error_internal,
"can only replace single child by leaf",
goto error);
return isl_schedule_tree_reset_children(tree);
}
if (!tree->children && pos == 0)
tree->children =
isl_schedule_tree_list_from_schedule_tree(child);
else
tree->children = isl_schedule_tree_list_set_schedule_tree(
tree->children, pos, child);
if (!tree->children)
return isl_schedule_tree_free(tree);
tree = isl_schedule_tree_update_anchored(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_schedule_tree_free(child);
return NULL;
}
/* Replace the (explicit) children of "tree" by "children"?
*/
__isl_give isl_schedule_tree *isl_schedule_tree_set_children(
__isl_take isl_schedule_tree *tree,
__isl_take isl_schedule_tree_list *children)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !children)
goto error;
isl_schedule_tree_list_free(tree->children);
tree->children = children;
return tree;
error:
isl_schedule_tree_free(tree);
isl_schedule_tree_list_free(children);
return NULL;
}
/* Create a new band schedule tree referring to "band"
* with "tree" as single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
__isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_band(band);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Create a new context schedule tree with the given context and
* with "tree" as single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
__isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_context(context);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Create a new domain schedule tree with the given domain and
* with "tree" as single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_domain(domain);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Create a new expansion schedule tree with the given contraction and
* expansion and with "tree" as single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
__isl_take isl_schedule_tree *tree,
__isl_take isl_union_pw_multi_aff *contraction,
__isl_take isl_union_map *expansion)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_expansion(contraction, expansion);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Create a new extension schedule tree with the given extension and
* with "tree" as single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_extension(extension);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Create a new filter schedule tree with the given filter and single child.
*
* If the root of "tree" is itself a filter node, then the two
* filter nodes are merged into one node.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
{
isl_schedule_tree *res;
if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
isl_union_set *tree_filter;
tree_filter = isl_schedule_tree_filter_get_filter(tree);
tree_filter = isl_union_set_intersect(tree_filter, filter);
tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
return tree;
}
res = isl_schedule_tree_from_filter(filter);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Insert a filter node with filter set "filter"
* in each of the children of "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
{
int i;
isl_size n;
n = isl_schedule_tree_n_children(tree);
if (n < 0 || !filter)
goto error;
for (i = 0; i < n; ++i) {
isl_schedule_tree *child;
child = isl_schedule_tree_get_child(tree, i);
child = isl_schedule_tree_insert_filter(child,
isl_union_set_copy(filter));
tree = isl_schedule_tree_replace_child(tree, i, child);
}
isl_union_set_free(filter);
return tree;
error:
isl_union_set_free(filter);
isl_schedule_tree_free(tree);
return NULL;
}
/* Create a new guard schedule tree with the given guard and
* with "tree" as single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
__isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_guard(guard);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Create a new mark schedule tree with the given mark identifier and
* single child.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
__isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
{
isl_schedule_tree *res;
res = isl_schedule_tree_from_mark(mark);
return isl_schedule_tree_replace_child(res, 0, tree);
}
/* Return the number of members in the band tree root.
*/
isl_size isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return isl_size_error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_size_error);
return isl_schedule_band_n_member(tree->band);
}
/* Is the band member at position "pos" of the band tree root
* marked coincident?
*/
isl_bool isl_schedule_tree_band_member_get_coincident(
__isl_keep isl_schedule_tree *tree, int pos)
{
if (!tree)
return isl_bool_error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_bool_error);
return isl_schedule_band_member_get_coincident(tree->band, pos);
}
/* Mark the given band member as being coincident or not
* according to "coincident".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
__isl_take isl_schedule_tree *tree, int pos, int coincident)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_schedule_tree_free(tree));
if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
coincident)
return tree;
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
coincident);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
}
/* Is the band tree root marked permutable?
*/
isl_bool isl_schedule_tree_band_get_permutable(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return isl_bool_error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_bool_error);
return isl_schedule_band_get_permutable(tree->band);
}
/* Mark the band tree root permutable or not according to "permutable"?
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
__isl_take isl_schedule_tree *tree, int permutable)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_schedule_tree_free(tree));
if (isl_schedule_tree_band_get_permutable(tree) == permutable)
return tree;
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
}
/* Return the schedule space of the band tree root.
*/
__isl_give isl_space *isl_schedule_tree_band_get_space(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return NULL);
return isl_schedule_band_get_space(tree->band);
}
/* Intersect the domain of the band schedule of the band tree root
* with "domain".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
{
if (!tree || !domain)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_union_set_free(domain);
return NULL;
}
/* Return the schedule of the band tree root in isolation.
*/
__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return NULL);
return isl_schedule_band_get_partial_schedule(tree->band);
}
/* Replace the schedule of the band tree root by "schedule".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
__isl_take isl_schedule_tree *tree,
__isl_take isl_multi_union_pw_aff *schedule)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !schedule)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return NULL);
tree->band = isl_schedule_band_set_partial_schedule(tree->band,
schedule);
return tree;
error:
isl_schedule_tree_free(tree);
isl_multi_union_pw_aff_free(schedule);
return NULL;
}
/* Return the loop AST generation type for the band member
* of the band tree root at position "pos".
*/
enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
__isl_keep isl_schedule_tree *tree, int pos)
{
if (!tree)
return isl_ast_loop_error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_ast_loop_error);
return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
}
/* Set the loop AST generation type for the band member of the band tree root
* at position "pos" to "type".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
__isl_take isl_schedule_tree *tree, int pos,
enum isl_ast_loop_type type)
{
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_schedule_tree_free(tree));
tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
pos, type);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
}
/* Return the loop AST generation type for the band member
* of the band tree root at position "pos" for the isolated part.
*/
enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
__isl_keep isl_schedule_tree *tree, int pos)
{
if (!tree)
return isl_ast_loop_error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_ast_loop_error);
return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
pos);
}
/* Set the loop AST generation type for the band member of the band tree root
* at position "pos" for the isolated part to "type".
*/
__isl_give isl_schedule_tree *
isl_schedule_tree_band_member_set_isolate_ast_loop_type(
__isl_take isl_schedule_tree *tree, int pos,
enum isl_ast_loop_type type)
{
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_schedule_tree_free(tree));
tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
tree->band, pos, type);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
}
/* Return the AST build options associated to the band tree root.
*/
__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return NULL);
return isl_schedule_band_get_ast_build_options(tree->band);
}
/* Replace the AST build options associated to band tree root by "options".
* Updated the anchored field if the anchoredness of the root node itself
* changes.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
{
int was_anchored;
tree = isl_schedule_tree_cow(tree);
if (!tree || !options)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
was_anchored = isl_schedule_tree_is_anchored(tree);
tree->band = isl_schedule_band_set_ast_build_options(tree->band,
options);
if (!tree->band)
return isl_schedule_tree_free(tree);
if (isl_schedule_tree_is_anchored(tree) != was_anchored)
tree = isl_schedule_tree_update_anchored(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_union_set_free(options);
return NULL;
}
/* Return the "isolate" option associated to the band tree root of "tree",
* which is assumed to appear at schedule depth "depth".
*/
__isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option(
__isl_keep isl_schedule_tree *tree, int depth)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return NULL);
return isl_schedule_band_get_ast_isolate_option(tree->band, depth);
}
/* Return the context of the context tree root.
*/
__isl_give isl_set *isl_schedule_tree_context_get_context(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_context)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a context node", return NULL);
return isl_set_copy(tree->context);
}
/* Return the domain of the domain tree root.
*/
__isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_domain)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a domain node", return NULL);
return isl_union_set_copy(tree->domain);
}
/* Replace the domain of domain tree root "tree" by "domain".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !domain)
goto error;
if (tree->type != isl_schedule_node_domain)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a domain node", goto error);
isl_union_set_free(tree->domain);
tree->domain = domain;
return tree;
error:
isl_schedule_tree_free(tree);
isl_union_set_free(domain);
return NULL;
}
/* Return the contraction of the expansion tree root.
*/
__isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_expansion)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not an expansion node", return NULL);
return isl_union_pw_multi_aff_copy(tree->contraction);
}
/* Return the expansion of the expansion tree root.
*/
__isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_expansion)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not an expansion node", return NULL);
return isl_union_map_copy(tree->expansion);
}
/* Replace the contraction and the expansion of the expansion tree root "tree"
* by "contraction" and "expansion".
*/
__isl_give isl_schedule_tree *
isl_schedule_tree_expansion_set_contraction_and_expansion(
__isl_take isl_schedule_tree *tree,
__isl_take isl_union_pw_multi_aff *contraction,
__isl_take isl_union_map *expansion)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !contraction || !expansion)
goto error;
if (tree->type != isl_schedule_node_expansion)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not an expansion node", return NULL);
isl_union_pw_multi_aff_free(tree->contraction);
tree->contraction = contraction;
isl_union_map_free(tree->expansion);
tree->expansion = expansion;
return tree;
error:
isl_schedule_tree_free(tree);
isl_union_pw_multi_aff_free(contraction);
isl_union_map_free(expansion);
return NULL;
}
/* Return the extension of the extension tree root.
*/
__isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
__isl_take isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_extension)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not an extension node", return NULL);
return isl_union_map_copy(tree->extension);
}
/* Replace the extension of extension tree root "tree" by "extension".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !extension)
goto error;
if (tree->type != isl_schedule_node_extension)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not an extension node", return NULL);
isl_union_map_free(tree->extension);
tree->extension = extension;
return tree;
error:
isl_schedule_tree_free(tree);
isl_union_map_free(extension);
return NULL;
}
/* Return the filter of the filter tree root.
*/
__isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_filter)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a filter node", return NULL);
return isl_union_set_copy(tree->filter);
}
/* Replace the filter of the filter tree root by "filter".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
{
tree = isl_schedule_tree_cow(tree);
if (!tree || !filter)
goto error;
if (tree->type != isl_schedule_node_filter)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a filter node", return NULL);
isl_union_set_free(tree->filter);
tree->filter = filter;
return tree;
error:
isl_schedule_tree_free(tree);
isl_union_set_free(filter);
return NULL;
}
/* Return the guard of the guard tree root.
*/
__isl_give isl_set *isl_schedule_tree_guard_get_guard(
__isl_take isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_guard)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a guard node", return NULL);
return isl_set_copy(tree->guard);
}
/* Return the mark identifier of the mark tree root "tree".
*/
__isl_give isl_id *isl_schedule_tree_mark_get_id(
__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_mark)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a mark node", return NULL);
return isl_id_copy(tree->mark);
}
/* Set dim to the range dimension of "map" and abort the search.
*/
static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
{
isl_size *dim = user;
*dim = isl_map_dim(map, isl_dim_out);
isl_map_free(map);
return isl_stat_error;
}
/* Return the dimension of the range of "umap".
* "umap" is assumed not to be empty and
* all maps inside "umap" are assumed to have the same range.
*
* We extract the range dimension from the first map in "umap".
*/
static isl_size range_dim(__isl_keep isl_union_map *umap)
{
isl_size dim = isl_size_error;
isl_size n;
n = isl_union_map_n_map(umap);
if (n < 0)
return isl_size_error;
if (n == 0)
isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
"unexpected empty input", return isl_size_error);
isl_union_map_foreach_map(umap, &set_range_dim, &dim);
return dim;
}
/* Append an "extra" number of zeros to the range of "umap" and
* return the result.
*/
static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
int extra)
{
isl_union_set *dom;
isl_space *space;
isl_multi_val *mv;
isl_union_pw_multi_aff *suffix;
isl_union_map *universe;
isl_union_map *suffix_umap;
universe = isl_union_map_universe(isl_union_map_copy(umap));
dom = isl_union_map_domain(universe);
space = isl_union_set_get_space(dom);
space = isl_space_set_from_params(space);
space = isl_space_add_dims(space, isl_dim_set, extra);
mv = isl_multi_val_zero(space);
suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
umap = isl_union_map_flat_range_product(umap, suffix_umap);
return umap;
}
/* Should we skip the root of "tree" while looking for the first
* descendant with schedule information?
* That is, is it impossible to derive any information about
* the iteration domain from this node?
*
* We do not want to skip leaf or error nodes because there is
* no point in looking any deeper from these nodes.
* We can only extract partial iteration domain information
* from an extension node, but extension nodes are not supported
* by the caller and it will error out on them.
*/
static isl_bool domain_less(__isl_keep isl_schedule_tree *tree)
{
enum isl_schedule_node_type type;
isl_size n;
type = isl_schedule_tree_get_type(tree);
switch (type) {
case isl_schedule_node_band:
n = isl_schedule_tree_band_n_member(tree);
return n < 0 ? isl_bool_error : isl_bool_ok(n == 0);
case isl_schedule_node_context:
case isl_schedule_node_guard:
case isl_schedule_node_mark:
return isl_bool_true;
case isl_schedule_node_leaf:
case isl_schedule_node_error:
case isl_schedule_node_domain:
case isl_schedule_node_expansion:
case isl_schedule_node_extension:
case isl_schedule_node_filter:
case isl_schedule_node_set:
case isl_schedule_node_sequence:
return isl_bool_false;
}
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"unhandled case", return isl_bool_error);
}
/* Move down to the first descendant of "tree" that contains any schedule
* information or return "leaf" if there is no such descendant.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
__isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
{
isl_bool down;
while ((down = domain_less(tree)) == isl_bool_true) {
if (!isl_schedule_tree_has_children(tree)) {
isl_schedule_tree_free(tree);
return isl_schedule_tree_copy(leaf);
}
tree = isl_schedule_tree_child(tree, 0);
}
if (down < 0)
return isl_schedule_tree_free(tree);
return tree;
}
static __isl_give isl_union_map *subtree_schedule_extend(
__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
/* Extend the schedule map "outer" with the subtree schedule
* of the (single) child of "tree", if any.
*
* If "tree" does not have any descendants (apart from those that
* do not carry any schedule information), then we simply return "outer".
* Otherwise, we extend the schedule map "outer" with the subtree schedule
* of the single child.
*/
static __isl_give isl_union_map *subtree_schedule_extend_child(
__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
{
isl_schedule_tree *child;
isl_union_map *res;
if (!tree)
return isl_union_map_free(outer);
if (!isl_schedule_tree_has_children(tree))
return outer;
child = isl_schedule_tree_get_child(tree, 0);
if (!child)
return isl_union_map_free(outer);
res = subtree_schedule_extend(child, outer);
isl_schedule_tree_free(child);
return res;
}
/* Extract the parameter space from one of the children of "tree",
* which are assumed to be filters.
*/
static __isl_give isl_space *extract_space_from_filter_child(
__isl_keep isl_schedule_tree *tree)
{
isl_space *space;
isl_union_set *dom;
isl_schedule_tree *child;
child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
dom = isl_schedule_tree_filter_get_filter(child);
space = isl_union_set_get_space(dom);
isl_union_set_free(dom);
isl_schedule_tree_free(child);
return space;
}
/* Extend the schedule map "outer" with the subtree schedule
* of a set or sequence node.
*
* The schedule for the set or sequence node itself is composed of
* pieces of the form
*
* filter -> []
*
* or
*
* filter -> [index]
*
* The first form is used if there is only a single child or
* if the current node is a set node and the schedule_separate_components
* option is not set.
*
* Each of the pieces above is extended with the subtree schedule of
* the child of the corresponding filter, if any, padded with zeros
* to ensure that all pieces have the same range dimension.
*/
static __isl_give isl_union_map *subtree_schedule_extend_from_children(
__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
{
int i;
isl_size n;
isl_size dim;
int separate;
isl_ctx *ctx;
isl_val *v = NULL;
isl_multi_val *mv;
isl_space *space;
isl_union_map *umap;
n = isl_schedule_tree_n_children(tree);
if (n < 0)
return isl_union_map_free(outer);
if (n == 0)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"missing children", return isl_union_map_free(outer));
ctx = isl_schedule_tree_get_ctx(tree);
separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
isl_options_get_schedule_separate_components(ctx));
space = isl_space_params_alloc(ctx, 0);
umap = isl_union_map_empty(isl_space_copy(space));
space = isl_space_set_from_params(space);
if (separate) {
space = isl_space_add_dims(space, isl_dim_set, 1);
v = isl_val_zero(ctx);
}
mv = isl_multi_val_zero(space);
dim = isl_multi_val_dim(mv, isl_dim_set);
if (dim < 0)
umap = isl_union_map_free(umap);
for (i = 0; i < n; ++i) {
isl_multi_val *mv_copy;
isl_union_pw_multi_aff *upma;
isl_union_map *umap_i;
isl_union_set *dom;
isl_schedule_tree *child;
isl_size dim_i;
isl_bool empty;
child = isl_schedule_tree_list_get_schedule_tree(
tree->children, i);
dom = isl_schedule_tree_filter_get_filter(child);
if (separate) {
mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
v = isl_val_add_ui(v, 1);
}
mv_copy = isl_multi_val_copy(mv);
space = isl_union_set_get_space(dom);
mv_copy = isl_multi_val_align_params(mv_copy, space);
upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv_copy);
umap_i = isl_union_map_from_union_pw_multi_aff(upma);
umap_i = isl_union_map_flat_range_product(
isl_union_map_copy(outer), umap_i);
umap_i = subtree_schedule_extend_child(child, umap_i);
isl_schedule_tree_free(child);
empty = isl_union_map_is_empty(umap_i);
if (empty < 0)
umap_i = isl_union_map_free(umap_i);
else if (empty) {
isl_union_map_free(umap_i);
continue;
}
dim_i = range_dim(umap_i);
if (dim_i < 0) {
umap = isl_union_map_free(umap);
} else if (dim < dim_i) {
umap = append_range(umap, dim_i - dim);
dim = dim_i;
} else if (dim_i < dim) {
umap_i = append_range(umap_i, dim - dim_i);
}
umap = isl_union_map_union(umap, umap_i);
}
isl_val_free(v);
isl_multi_val_free(mv);
isl_union_map_free(outer);
return umap;
}
/* Extend the schedule map "outer" with the subtree schedule of "tree".
*
* If the root of the tree is a set or a sequence, then we extend
* the schedule map in subtree_schedule_extend_from_children.
* Otherwise, we extend the schedule map with the partial schedule
* corresponding to the root of the tree and then continue with
* the single child of this root.
* In the special case of an expansion, the schedule map is "extended"
* by applying the expansion to the domain of the schedule map.
*/
static __isl_give isl_union_map *subtree_schedule_extend(
__isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
{
isl_multi_union_pw_aff *mupa;
isl_union_map *umap;
isl_union_set *domain;
isl_size n;
if (!tree)
return NULL;
switch (tree->type) {
case isl_schedule_node_error:
return isl_union_map_free(outer);
case isl_schedule_node_extension:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"cannot construct subtree schedule of tree "
"with extension nodes",
return isl_union_map_free(outer));
case isl_schedule_node_context:
case isl_schedule_node_guard:
case isl_schedule_node_mark:
return subtree_schedule_extend_child(tree, outer);
case isl_schedule_node_band:
n = isl_schedule_tree_band_n_member(tree);
if (n < 0)
return isl_union_map_free(outer);
if (n == 0)
return subtree_schedule_extend_child(tree, outer);
mupa = isl_schedule_band_get_partial_schedule(tree->band);
umap = isl_union_map_from_multi_union_pw_aff(mupa);
outer = isl_union_map_flat_range_product(outer, umap);
umap = subtree_schedule_extend_child(tree, outer);
break;
case isl_schedule_node_domain:
domain = isl_schedule_tree_domain_get_domain(tree);
umap = isl_union_map_from_domain(domain);
outer = isl_union_map_flat_range_product(outer, umap);
umap = subtree_schedule_extend_child(tree, outer);
break;
case isl_schedule_node_expansion:
umap = isl_schedule_tree_expansion_get_expansion(tree);
outer = isl_union_map_apply_domain(outer, umap);
umap = subtree_schedule_extend_child(tree, outer);
break;
case isl_schedule_node_filter:
domain = isl_schedule_tree_filter_get_filter(tree);
umap = isl_union_map_from_domain(domain);
outer = isl_union_map_flat_range_product(outer, umap);
umap = subtree_schedule_extend_child(tree, outer);
break;
case isl_schedule_node_leaf:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"leaf node should be handled by caller", return NULL);
case isl_schedule_node_set:
case isl_schedule_node_sequence:
umap = subtree_schedule_extend_from_children(tree, outer);
break;
}
return umap;
}
static __isl_give isl_union_set *initial_domain(
__isl_keep isl_schedule_tree *tree);
/* Extract a universe domain from the children of the tree root "tree",
* which is a set or sequence, meaning that its children are filters.
* In particular, return the union of the universes of the filters.
*/
static __isl_give isl_union_set *initial_domain_from_children(
__isl_keep isl_schedule_tree *tree)
{
int i;
isl_size n;
isl_space *space;
isl_union_set *domain;
n = isl_schedule_tree_n_children(tree);
if (n < 0)
return NULL;
if (n == 0)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"missing children", return NULL);
space = extract_space_from_filter_child(tree);
domain = isl_union_set_empty(space);
for (i = 0; i < n; ++i) {
isl_schedule_tree *child;
isl_union_set *domain_i;
child = isl_schedule_tree_get_child(tree, i);
domain_i = initial_domain(child);
domain = isl_union_set_union(domain, domain_i);
isl_schedule_tree_free(child);
}
return domain;
}
/* Extract a universe domain from the tree root "tree".
* The caller is responsible for making sure that this node
* would not be skipped by isl_schedule_tree_first_schedule_descendant
* and that it is not a leaf node.
*/
static __isl_give isl_union_set *initial_domain(
__isl_keep isl_schedule_tree *tree)
{
isl_multi_union_pw_aff *mupa;
isl_union_set *domain;
isl_union_map *exp;
isl_size n;
if (!tree)
return NULL;
switch (tree->type) {
case isl_schedule_node_error:
return NULL;
case isl_schedule_node_context:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"context node should be handled by caller",
return NULL);
case isl_schedule_node_guard:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"guard node should be handled by caller",
return NULL);
case isl_schedule_node_mark:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"mark node should be handled by caller",
return NULL);
case isl_schedule_node_extension:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"cannot construct subtree schedule of tree "
"with extension nodes", return NULL);
case isl_schedule_node_band:
n = isl_schedule_tree_band_n_member(tree);
if (n < 0)
return NULL;
if (n == 0)
isl_die(isl_schedule_tree_get_ctx(tree),
isl_error_internal,
"0D band should be handled by caller",
return NULL);
mupa = isl_schedule_band_get_partial_schedule(tree->band);
domain = isl_multi_union_pw_aff_domain(mupa);
domain = isl_union_set_universe(domain);
break;
case isl_schedule_node_domain:
domain = isl_schedule_tree_domain_get_domain(tree);
domain = isl_union_set_universe(domain);
break;
case isl_schedule_node_expansion:
exp = isl_schedule_tree_expansion_get_expansion(tree);
exp = isl_union_map_universe(exp);
domain = isl_union_map_domain(exp);
break;
case isl_schedule_node_filter:
domain = isl_schedule_tree_filter_get_filter(tree);
domain = isl_union_set_universe(domain);
break;
case isl_schedule_node_leaf:
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"leaf node should be handled by caller", return NULL);
case isl_schedule_node_set:
case isl_schedule_node_sequence:
domain = initial_domain_from_children(tree);
break;
}
return domain;
}
/* Return the subtree schedule of a node that contains some schedule
* information, i.e., a node that would not be skipped by
* isl_schedule_tree_first_schedule_descendant and that is not a leaf.
*
* If the tree contains any expansions, then the returned subtree
* schedule is formulated in terms of the expanded domains.
* The tree is not allowed to contain any extension nodes.
*
* We start with an initial zero-dimensional subtree schedule based
* on the domain information in the root node and then extend it
* based on the schedule information in the root node and its descendants.
*/
__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
__isl_keep isl_schedule_tree *tree)
{
isl_union_set *domain;
isl_union_map *umap;
domain = initial_domain(tree);
umap = isl_union_map_from_domain(domain);
return subtree_schedule_extend(tree, umap);
}
/* Multiply the partial schedule of the band root node of "tree"
* with the factors in "mv".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
{
if (!tree || !mv)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
tree->band = isl_schedule_band_scale(tree->band, mv);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_multi_val_free(mv);
return NULL;
}
/* Divide the partial schedule of the band root node of "tree"
* by the factors in "mv".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
{
if (!tree || !mv)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
tree->band = isl_schedule_band_scale_down(tree->band, mv);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_multi_val_free(mv);
return NULL;
}
/* Reduce the partial schedule of the band root node of "tree"
* modulo the factors in "mv".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
{
if (!tree || !mv)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
tree->band = isl_schedule_band_mod(tree->band, mv);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_multi_val_free(mv);
return NULL;
}
/* Shift the partial schedule of the band root node of "tree" by "shift".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
__isl_take isl_schedule_tree *tree,
__isl_take isl_multi_union_pw_aff *shift)
{
if (!tree || !shift)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
tree->band = isl_schedule_band_shift(tree->band, shift);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
error:
isl_schedule_tree_free(tree);
isl_multi_union_pw_aff_free(shift);
return NULL;
}
/* Given two trees with sequence roots, replace the child at position
* "pos" of "tree" with the children of "child".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
__isl_take isl_schedule_tree *tree, int pos,
__isl_take isl_schedule_tree *child)
{
isl_size n;
isl_schedule_tree_list *list1, *list2;
tree = isl_schedule_tree_cow(tree);
if (!tree || !child)
goto error;
if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a sequence node", goto error);
n = isl_schedule_tree_n_children(tree);
if (n < 0)
goto error;
if (pos < 0 || pos >= n)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"position out of bounds", goto error);
if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a sequence node", goto error);
list1 = isl_schedule_tree_list_copy(tree->children);
list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
list2 = isl_schedule_tree_list_copy(tree->children);
list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
list1 = isl_schedule_tree_list_concat(list1,
isl_schedule_tree_list_copy(child->children));
list1 = isl_schedule_tree_list_concat(list1, list2);
isl_schedule_tree_free(tree);
isl_schedule_tree_free(child);
return isl_schedule_tree_from_children(isl_schedule_node_sequence,
list1);
error:
isl_schedule_tree_free(tree);
isl_schedule_tree_free(child);
return NULL;
}
/* Tile the band root node of "tree" with tile sizes "sizes".
*
* We duplicate the band node, change the schedule of one of them
* to the tile schedule and the other to the point schedule and then
* attach the point band as a child to the tile band.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
__isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
{
isl_schedule_tree *child = NULL;
if (!tree || !sizes)
goto error;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
child = isl_schedule_tree_copy(tree);
tree = isl_schedule_tree_cow(tree);
child = isl_schedule_tree_cow(child);
if (!tree || !child)
goto error;
tree->band = isl_schedule_band_tile(tree->band,
isl_multi_val_copy(sizes));
if (!tree->band)
goto error;
child->band = isl_schedule_band_point(child->band, tree->band, sizes);
if (!child->band)
child = isl_schedule_tree_free(child);
tree = isl_schedule_tree_replace_child(tree, 0, child);
return tree;
error:
isl_schedule_tree_free(child);
isl_schedule_tree_free(tree);
isl_multi_val_free(sizes);
return NULL;
}
/* Given an isolate AST generation option "isolate" for a band of size pos + n,
* return the corresponding option for a band covering the first "pos"
* members.
*
* The input isolate option is of the form
*
* isolate[[flattened outer bands] -> [pos; n]]
*
* The output isolate option is of the form
*
* isolate[[flattened outer bands] -> [pos]]
*/
static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate,
int pos, int n)
{
isl_id *id;
isl_map *map;
isolate = isl_set_copy(isolate);
id = isl_set_get_tuple_id(isolate);
map = isl_set_unwrap(isolate);
map = isl_map_project_out(map, isl_dim_out, pos, n);
isolate = isl_map_wrap(map);
isolate = isl_set_set_tuple_id(isolate, id);
return isolate;
}
/* Given an isolate AST generation option "isolate" for a band of size pos + n,
* return the corresponding option for a band covering the final "n"
* members within a band covering the first "pos" members.
*
* The input isolate option is of the form
*
* isolate[[flattened outer bands] -> [pos; n]]
*
* The output isolate option is of the form
*
* isolate[[flattened outer bands; pos] -> [n]]
*
*
* The range is first split into
*
* isolate[[flattened outer bands] -> [[pos] -> [n]]]
*
* and then the first pos members are moved to the domain
*
* isolate[[[flattened outer bands] -> [pos]] -> [n]]
*
* after which the domain is flattened to obtain the desired output.
*/
static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate,
int pos, int n)
{
isl_id *id;
isl_space *space;
isl_multi_aff *ma1, *ma2;
isl_map *map;
isolate = isl_set_copy(isolate);
id = isl_set_get_tuple_id(isolate);
map = isl_set_unwrap(isolate);
space = isl_space_range(isl_map_get_space(map));
ma1 = isl_multi_aff_project_out_map(isl_space_copy(space),
isl_dim_set, pos, n);
ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos);
ma1 = isl_multi_aff_range_product(ma1, ma2);
map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1));
map = isl_map_uncurry(map);
map = isl_map_flatten_domain(map);
isolate = isl_map_wrap(map);
isolate = isl_set_set_tuple_id(isolate, id);
return isolate;
}
/* Split the band root node of "tree" into two nested band nodes,
* one with the first "pos" dimensions and
* one with the remaining dimensions.
* The tree is itself positioned at schedule depth "depth".
*
* The loop AST generation type options and the isolate option
* are split over the two band nodes.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_split(
__isl_take isl_schedule_tree *tree, int pos, int depth)
{
isl_size n;
isl_set *isolate, *tree_isolate, *child_isolate;
isl_schedule_tree *child;
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", return isl_schedule_tree_free(tree));
n = isl_schedule_tree_band_n_member(tree);
if (n < 0)
return isl_schedule_tree_free(tree);
if (pos < 0 || pos > n)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"position out of bounds",
return isl_schedule_tree_free(tree));
child = isl_schedule_tree_copy(tree);
tree = isl_schedule_tree_cow(tree);
child = isl_schedule_tree_cow(child);
if (!tree || !child)
goto error;
isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth);
tree_isolate = isolate_initial(isolate, pos, n - pos);
child_isolate = isolate_final(isolate, pos, n - pos);
child->band = isl_schedule_band_drop(child->band, 0, pos);
child->band = isl_schedule_band_replace_ast_build_option(child->band,
isl_set_copy(isolate), child_isolate);
tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
tree->band = isl_schedule_band_replace_ast_build_option(tree->band,
isl_set_copy(isolate), tree_isolate);
isl_set_free(isolate);
if (!child->band || !tree->band)
goto error;
tree = isl_schedule_tree_replace_child(tree, 0, child);
return tree;
error:
isl_schedule_tree_free(child);
isl_schedule_tree_free(tree);
return NULL;
}
/* Attach "tree2" at each of the leaves of "tree1".
*
* If "tree1" does not have any explicit children, then make "tree2"
* its single child. Otherwise, attach "tree2" to the leaves of
* each of the children of "tree1".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
__isl_take isl_schedule_tree *tree1,
__isl_take isl_schedule_tree *tree2)
{
int i;
isl_size n;
n = isl_schedule_tree_n_children(tree1);
if (n < 0 || !tree2)
goto error;
if (n == 0) {
isl_schedule_tree_list *list;
list = isl_schedule_tree_list_from_schedule_tree(tree2);
tree1 = isl_schedule_tree_set_children(tree1, list);
return tree1;
}
for (i = 0; i < n; ++i) {
isl_schedule_tree *child;
child = isl_schedule_tree_get_child(tree1, i);
child = isl_schedule_tree_append_to_leaves(child,
isl_schedule_tree_copy(tree2));
tree1 = isl_schedule_tree_replace_child(tree1, i, child);
}
isl_schedule_tree_free(tree2);
return tree1;
error:
isl_schedule_tree_free(tree1);
isl_schedule_tree_free(tree2);
return NULL;
}
/* Reset the user pointer on all identifiers of parameters and tuples
* in the root of "tree".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
__isl_take isl_schedule_tree *tree)
{
if (isl_schedule_tree_is_leaf(tree))
return tree;
tree = isl_schedule_tree_cow(tree);
if (!tree)
return NULL;
switch (tree->type) {
case isl_schedule_node_error:
return isl_schedule_tree_free(tree);
case isl_schedule_node_band:
tree->band = isl_schedule_band_reset_user(tree->band);
if (!tree->band)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_context:
tree->context = isl_set_reset_user(tree->context);
if (!tree->context)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_domain:
tree->domain = isl_union_set_reset_user(tree->domain);
if (!tree->domain)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_expansion:
tree->contraction =
isl_union_pw_multi_aff_reset_user(tree->contraction);
tree->expansion = isl_union_map_reset_user(tree->expansion);
if (!tree->contraction || !tree->expansion)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_extension:
tree->extension = isl_union_map_reset_user(tree->extension);
if (!tree->extension)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_filter:
tree->filter = isl_union_set_reset_user(tree->filter);
if (!tree->filter)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_guard:
tree->guard = isl_set_reset_user(tree->guard);
if (!tree->guard)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
break;
}
return tree;
}
/* Align the parameters of the root of "tree" to those of "space".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_align_params(
__isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
{
if (!space)
goto error;
if (isl_schedule_tree_is_leaf(tree)) {
isl_space_free(space);
return tree;
}
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
switch (tree->type) {
case isl_schedule_node_error:
goto error;
case isl_schedule_node_band:
tree->band = isl_schedule_band_align_params(tree->band, space);
if (!tree->band)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_context:
tree->context = isl_set_align_params(tree->context, space);
if (!tree->context)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_domain:
tree->domain = isl_union_set_align_params(tree->domain, space);
if (!tree->domain)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_expansion:
tree->contraction =
isl_union_pw_multi_aff_align_params(tree->contraction,
isl_space_copy(space));
tree->expansion = isl_union_map_align_params(tree->expansion,
space);
if (!tree->contraction || !tree->expansion)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_extension:
tree->extension = isl_union_map_align_params(tree->extension,
space);
if (!tree->extension)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_filter:
tree->filter = isl_union_set_align_params(tree->filter, space);
if (!tree->filter)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_guard:
tree->guard = isl_set_align_params(tree->guard, space);
if (!tree->guard)
return isl_schedule_tree_free(tree);
break;
case isl_schedule_node_leaf:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
isl_space_free(space);
break;
}
return tree;
error:
isl_space_free(space);
isl_schedule_tree_free(tree);
return NULL;
}
/* Does "tree" involve the iteration domain?
* That is, does it need to be modified
* by isl_schedule_tree_pullback_union_pw_multi_aff?
*/
static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
{
if (!tree)
return -1;
switch (tree->type) {
case isl_schedule_node_error:
return -1;
case isl_schedule_node_band:
case isl_schedule_node_domain:
case isl_schedule_node_expansion:
case isl_schedule_node_extension:
case isl_schedule_node_filter:
return 1;
case isl_schedule_node_context:
case isl_schedule_node_leaf:
case isl_schedule_node_guard:
case isl_schedule_node_mark:
case isl_schedule_node_sequence:
case isl_schedule_node_set:
return 0;
}
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
"unhandled case", return -1);
}
/* Compute the pullback of the root node of "tree" by the function
* represented by "upma".
* In other words, plug in "upma" in the iteration domains of
* the root node of "tree".
* We currently do not handle expansion nodes.
*
* We first check if the root node involves any iteration domains.
* If so, we handle the specific cases.
*/
__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
__isl_take isl_schedule_tree *tree,
__isl_take isl_union_pw_multi_aff *upma)
{
int involves;
if (!tree || !upma)
goto error;
involves = involves_iteration_domain(tree);
if (involves < 0)
goto error;
if (!involves) {
isl_union_pw_multi_aff_free(upma);
return tree;
}
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
if (tree->type == isl_schedule_node_band) {
tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
tree->band, upma);
if (!tree->band)
return isl_schedule_tree_free(tree);
} else if (tree->type == isl_schedule_node_domain) {
tree->domain =
isl_union_set_preimage_union_pw_multi_aff(tree->domain,
upma);
if (!tree->domain)
return isl_schedule_tree_free(tree);
} else if (tree->type == isl_schedule_node_expansion) {
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
"cannot pullback expansion node", goto error);
} else if (tree->type == isl_schedule_node_extension) {
tree->extension =
isl_union_map_preimage_range_union_pw_multi_aff(
tree->extension, upma);
if (!tree->extension)
return isl_schedule_tree_free(tree);
} else if (tree->type == isl_schedule_node_filter) {
tree->filter =
isl_union_set_preimage_union_pw_multi_aff(tree->filter,
upma);
if (!tree->filter)
return isl_schedule_tree_free(tree);
}
return tree;
error:
isl_union_pw_multi_aff_free(upma);
isl_schedule_tree_free(tree);
return NULL;
}
/* Compute the gist of the band tree root with respect to "context".
*/
__isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
__isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
{
if (!tree)
return NULL;
if (tree->type != isl_schedule_node_band)
isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
"not a band node", goto error);
tree = isl_schedule_tree_cow(tree);
if (!tree)
goto error;
tree->band = isl_schedule_band_gist(tree->band, context);
if (!tree->band)
return isl_schedule_tree_free(tree);
return tree;
error:
isl_union_set_free(context);
isl_schedule_tree_free(tree);
return NULL;
}
/* Are any members in "band" marked coincident?
*/
static isl_bool any_coincident(__isl_keep isl_schedule_band *band)
{
int i;
isl_size n;
n = isl_schedule_band_n_member(band);
if (n < 0)
return isl_bool_error;
for (i = 0; i < n; ++i) {
isl_bool coincident;
coincident = isl_schedule_band_member_get_coincident(band, i);
if (coincident < 0 || coincident)
return coincident;
}
return isl_bool_false;
}
/* Print the band node "band" to "p".
*
* The permutable and coincident properties are only printed if they
* are different from the defaults.
* The coincident property is always printed in YAML flow style.
*/
static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
__isl_keep isl_schedule_band *band)
{
isl_union_set *options;
isl_bool empty;
isl_bool coincident;
p = isl_printer_print_str(p, "schedule");
p = isl_printer_yaml_next(p);
p = isl_printer_print_str(p, "\"");
p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
p = isl_printer_print_str(p, "\"");
if (isl_schedule_band_get_permutable(band)) {
p = isl_printer_yaml_next(p);
p = isl_printer_print_str(p, "permutable");
p = isl_printer_yaml_next(p);
p = isl_printer_print_int(p, 1);
}
coincident = any_coincident(band);
if (coincident < 0)
return isl_printer_free(p);
if (coincident) {
int i;
isl_size n;
int style;
p = isl_printer_yaml_next(p);
p = isl_printer_print_str(p, "coincident");
p = isl_printer_yaml_next(p);
style = isl_printer_get_yaml_style(p);
p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
p = isl_printer_yaml_start_sequence(p);
n = isl_schedule_band_n_member(band);
if (n < 0)
return isl_printer_free(p);
for (i = 0; i < n; ++i) {
p = isl_printer_print_int(p,
isl_schedule_band_member_get_coincident(band, i));
p = isl_printer_yaml_next(p);
}
p = isl_printer_yaml_end_sequence(p);
p = isl_printer_set_yaml_style(p, style);
}
options = isl_schedule_band_get_ast_build_options(band);
empty = isl_union_set_is_empty(options);
if (empty < 0)
p = isl_printer_free(p);
if (!empty) {
p = isl_printer_yaml_next(p);
p = isl_printer_print_str(p, "options");
p = isl_printer_yaml_next(p);
p = isl_printer_print_str(p, "\"");
p = isl_printer_print_union_set(p, options);
p = isl_printer_print_str(p, "\"");
}
isl_union_set_free(options);
return p;
}
#undef BASE
#define BASE str
#define isl_str const char
#include "print_yaml_field_templ.c"
#undef BASE
#define BASE set
#include "print_yaml_field_templ.c"
#undef BASE
#define BASE union_set
#include "print_yaml_field_templ.c"
#undef BASE
#define BASE union_map
#include "print_yaml_field_templ.c"
#undef BASE
#define BASE union_pw_multi_aff
#include "print_yaml_field_templ.c"
/* Print "tree" to "p".
*
* If "n_ancestor" is non-negative, then "child_pos" contains the child
* positions of a descendant of the current node that should be marked
* (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
* is zero, then the current node should be marked.
* The marking is only printed in YAML block format.
*
* Implicit leaf nodes are not printed, except if they correspond
* to the node that should be marked.
*/
__isl_give isl_printer *isl_printer_print_schedule_tree_mark(
__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
int n_ancestor, int *child_pos)
{
int i;
isl_size n;
int sequence = 0;
int block;
block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
p = isl_printer_yaml_start_mapping(p);
if (n_ancestor == 0 && block) {
p = isl_printer_print_str(p, "# YOU ARE HERE");
p = isl_printer_end_line(p);
p = isl_printer_start_line(p);
}
switch (tree->type) {
case isl_schedule_node_error:
p = isl_printer_print_str(p, "ERROR");
p = isl_printer_yaml_next(p);
break;
case isl_schedule_node_leaf:
p = isl_printer_print_str(p, "leaf");
p = isl_printer_yaml_next(p);
break;
case isl_schedule_node_sequence:
p = isl_printer_print_str(p, "sequence");
p = isl_printer_yaml_next(p);
sequence = 1;
break;
case isl_schedule_node_set:
p = isl_printer_print_str(p, "set");
p = isl_printer_yaml_next(p);
sequence = 1;
break;
case isl_schedule_node_context:
p = print_yaml_field_set(p, "context", tree->context);
break;
case isl_schedule_node_domain:
p = print_yaml_field_union_set(p, "domain", tree->domain);
break;
case isl_schedule_node_expansion:
p = print_yaml_field_union_pw_multi_aff(p, "contraction",
tree->contraction);
p = print_yaml_field_union_map(p, "expansion", tree->expansion);
break;
case isl_schedule_node_extension:
p = print_yaml_field_union_map(p, "extension", tree->extension);
break;
case isl_schedule_node_filter:
p = print_yaml_field_union_set(p, "filter", tree->filter);
break;
case isl_schedule_node_guard:
p = print_yaml_field_set(p, "guard", tree->guard);
break;
case isl_schedule_node_mark:
p = print_yaml_field_str(p, "mark",
isl_id_get_name(tree->mark));
break;
case isl_schedule_node_band:
p = print_tree_band(p, tree->band);
p = isl_printer_yaml_next(p);
break;
}
n = isl_schedule_tree_n_children(tree);
if (n < 0)
return isl_printer_free(p);
if (n == 0) {
if (n_ancestor > 0 && block) {
isl_schedule_tree *leaf;
p = isl_printer_print_str(p, "child");
p = isl_printer_yaml_next(p);
leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
p = isl_printer_print_schedule_tree_mark(p,
leaf, 0, NULL);
isl_schedule_tree_free(leaf);
p = isl_printer_yaml_next(p);
}
return isl_printer_yaml_end_mapping(p);
}
if (sequence) {
p = isl_printer_yaml_start_sequence(p);
} else {
p = isl_printer_print_str(p, "child");
p = isl_printer_yaml_next(p);
}
for (i = 0; i < n; ++i) {
isl_schedule_tree *t;
t = isl_schedule_tree_get_child(tree, i);
if (n_ancestor > 0 && child_pos[0] == i)
p = isl_printer_print_schedule_tree_mark(p, t,
n_ancestor - 1, child_pos + 1);
else
p = isl_printer_print_schedule_tree_mark(p, t,
-1, NULL);
isl_schedule_tree_free(t);
p = isl_printer_yaml_next(p);
}
if (sequence)
p = isl_printer_yaml_end_sequence(p);
p = isl_printer_yaml_end_mapping(p);
return p;
}
/* Print "tree" to "p".
*/
__isl_give isl_printer *isl_printer_print_schedule_tree(
__isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
{
return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
}
void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
{
isl_ctx *ctx;
isl_printer *printer;
if (!tree)
return;
ctx = isl_schedule_tree_get_ctx(tree);
printer = isl_printer_to_file(ctx, stderr);
printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
printer = isl_printer_print_schedule_tree(printer, tree);
isl_printer_free(printer);
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/mirrors/isl.git
git@gitee.com:mirrors/isl.git
mirrors
isl
isl
master

搜索帮助