#include "llvm/IR/IRBuilder.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "isl/map.h"
/// @param P A reference to the pass this function is called from.
/// The pass is needed to update other analysis.
static void generate(IRBuilder<> &Builder, ScopStmt &Stmt,
- ValueMapT &GlobalMap, Pass *P) {
+ ValueMapT &GlobalMap, LoopToScevMapT <S, Pass *P) {
BlockGenerator Generator(Builder, Stmt, P);
- Generator.copyBB(GlobalMap);
+ Generator.copyBB(GlobalMap, LTS);
}
protected:
/// @param GlobalMap A mapping from old values to their new values
/// (for values recalculated in the new ScoP, but not
/// within this basic block).
+ /// @param LTS A mapping from loops virtual canonical induction
+ /// variable to their new values
+ /// (for values recalculated in the new ScoP, but not
+ /// within this basic block).
///
/// @returns o The old value, if it is still valid.
/// o The new value, if available.
/// o NULL, if no value is found.
- Value *getNewValue(const Value *Old, ValueMapT &BBMap, ValueMapT &GlobalMap);
+ Value *getNewValue(const Value *Old, ValueMapT &BBMap, ValueMapT &GlobalMap,
+ LoopToScevMapT <S);
void copyInstScalar(const Instruction *Inst, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap, LoopToScevMapT <S);
/// @brief Get the memory access offset to be added to the base address
std::vector<Value*> getMemoryAccessIndex(__isl_keep isl_map *AccessRelation,
Value *BaseAddress, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap,
+ LoopToScevMapT <S);
/// @brief Get the new operand address according to the changed access in
/// JSCOP file.
Value *getNewAccessOperand(__isl_keep isl_map *NewAccessRelation,
Value *BaseAddress, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap, LoopToScevMapT <S);
/// @brief Generate the operand address
Value *generateLocationAccessed(const Instruction *Inst,
const Value *Pointer, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap, LoopToScevMapT <S);
Value *generateScalarLoad(const LoadInst *load, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap, LoopToScevMapT <S);
Value *generateScalarStore(const StoreInst *store, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap, LoopToScevMapT <S);
/// @brief Copy a single Instruction.
///
/// (for values recalculated in the new ScoP, but not
/// within this basic block).
void copyInstruction(const Instruction *Inst, ValueMapT &BBMap,
- ValueMapT &GlobalMap);
+ ValueMapT &GlobalMap, LoopToScevMapT <S);
/// @brief Copy the basic block.
///
/// @param GlobalMap A mapping from old values to their new values
/// (for values recalculated in the new ScoP, but not
/// within this basic block).
- void copyBB(ValueMapT &GlobalMap);
+ void copyBB(ValueMapT &GlobalMap, LoopToScevMapT <S);
};
/// @brief Generate a new vector basic block for a polyhedral statement.
/// The pass is needed to update other analysis.
static void generate(IRBuilder<> &B, ScopStmt &Stmt,
VectorValueMapT &GlobalMaps,
+ std::vector<LoopToScevMapT> &VLTS,
__isl_keep isl_map *Schedule,
Pass *P) {
- VectorBlockGenerator Generator(B, GlobalMaps, Stmt, Schedule, P);
+ VectorBlockGenerator Generator(B, GlobalMaps, VLTS, Stmt, Schedule, P);
Generator.copyBB();
}
// all referenes to the old instructions with their recalculated values.
VectorValueMapT &GlobalMaps;
+ // This is a vector of loop->scev maps. The first map is used for the first
+ // vector lane, ...
+ // Each map, contains information about Instructions in the old ScoP, which
+ // are recalculated in the new SCoP. When copying the basic block, we replace
+ // all referenes to the old instructions with their recalculated values.
+ //
+ // For example, when the code generator produces this AST:
+ //
+ // for (int c1 = 0; c1 <= 1023; c1 += 1)
+ // for (int c2 = 0; c2 <= 1023; c2 += VF)
+ // for (int lane = 0; lane <= VF; lane += 1)
+ // Stmt(c2 + lane + 3, c1);
+ //
+ // VLTS[lane] contains a map:
+ // "outer loop in the old loop nest" -> SCEV("c2 + lane + 3"),
+ // "inner loop in the old loop nest" -> SCEV("c1").
+ std::vector<LoopToScevMapT> &VLTS;
+
// A map from the statement to a schedule where the innermost dimension is the
// dimension of the innermost loop containing the statemenet.
isl_map *Schedule;
VectorBlockGenerator(IRBuilder<> &B, VectorValueMapT &GlobalMaps,
+ std::vector<LoopToScevMapT> &VLTS,
ScopStmt &Stmt, __isl_keep isl_map *Schedule,
Pass *P);
}
Value *BlockGenerator::getNewValue(const Value *Old, ValueMapT &BBMap,
- ValueMapT &GlobalMap) {
+ ValueMapT &GlobalMap, LoopToScevMapT <S) {
// We assume constants never change.
// This avoids map lookups for many calls to this function.
if (isa<Constant>(Old))
}
void BlockGenerator::copyInstScalar(const Instruction *Inst, ValueMapT &BBMap,
- ValueMapT &GlobalMap) {
+ ValueMapT &GlobalMap, LoopToScevMapT <S) {
Instruction *NewInst = Inst->clone();
// Replace old operands with the new ones.
OE = Inst->op_end();
OI != OE; ++OI) {
Value *OldOperand = *OI;
- Value *NewOperand = getNewValue(OldOperand, BBMap, GlobalMap);
+ Value *NewOperand = getNewValue(OldOperand, BBMap, GlobalMap, LTS);
if (!NewOperand) {
assert(!isa<StoreInst>(NewInst) &&
std::vector<Value *> BlockGenerator::getMemoryAccessIndex(
__isl_keep isl_map *AccessRelation, Value *BaseAddress, ValueMapT &BBMap,
- ValueMapT &GlobalMap) {
+ ValueMapT &GlobalMap, LoopToScevMapT <S) {
assert((isl_map_dim(AccessRelation, isl_dim_out) == 1) &&
"Only single dimensional access functions supported");
std::vector<Value *> IVS;
for (unsigned i = 0; i < Statement.getNumIterators(); ++i) {
const Value *OriginalIV = Statement.getInductionVariableForDimension(i);
- Value *NewIV = getNewValue(OriginalIV, BBMap, GlobalMap);
+ Value *NewIV = getNewValue(OriginalIV, BBMap, GlobalMap, LTS);
IVS.push_back(NewIV);
}
Value *BlockGenerator::getNewAccessOperand(
__isl_keep isl_map *NewAccessRelation, Value *BaseAddress, ValueMapT &BBMap,
- ValueMapT &GlobalMap) {
+ ValueMapT &GlobalMap, LoopToScevMapT <S) {
std::vector<Value *> IndexArray =
- getMemoryAccessIndex(NewAccessRelation, BaseAddress, BBMap, GlobalMap);
+ getMemoryAccessIndex(NewAccessRelation, BaseAddress, BBMap, GlobalMap,
+ LTS);
Value *NewOperand =
Builder.CreateGEP(BaseAddress, IndexArray, "p_newarrayidx_");
return NewOperand;
Value *BlockGenerator::generateLocationAccessed(
const Instruction *Inst, const Value *Pointer, ValueMapT &BBMap,
- ValueMapT &GlobalMap) {
+ ValueMapT &GlobalMap, LoopToScevMapT <S) {
MemoryAccess &Access = Statement.getAccessFor(Inst);
isl_map *CurrentAccessRelation = Access.getAccessRelation();
isl_map *NewAccessRelation = Access.getNewAccessRelation();
Value *NewPointer;
if (!NewAccessRelation) {
- NewPointer = getNewValue(Pointer, BBMap, GlobalMap);
+ NewPointer = getNewValue(Pointer, BBMap, GlobalMap, LTS);
} else {
Value *BaseAddress = const_cast<Value *>(Access.getBaseAddr());
NewPointer =
- getNewAccessOperand(NewAccessRelation, BaseAddress, BBMap, GlobalMap);
+ getNewAccessOperand(NewAccessRelation, BaseAddress, BBMap, GlobalMap,
+ LTS);
}
isl_map_free(CurrentAccessRelation);
}
Value *BlockGenerator::generateScalarLoad(
- const LoadInst *Load, ValueMapT &BBMap, ValueMapT &GlobalMap) {
+ const LoadInst *Load, ValueMapT &BBMap, ValueMapT &GlobalMap,
+ LoopToScevMapT <S) {
const Value *Pointer = Load->getPointerOperand();
const Instruction *Inst = dyn_cast<Instruction>(Load);
- Value *NewPointer = generateLocationAccessed(Inst, Pointer, BBMap, GlobalMap);
+ Value *NewPointer = generateLocationAccessed(Inst, Pointer, BBMap, GlobalMap,
+ LTS);
Value *ScalarLoad =
Builder.CreateLoad(NewPointer, Load->getName() + "_p_scalar_");
return ScalarLoad;
}
Value *BlockGenerator::generateScalarStore(
- const StoreInst *Store, ValueMapT &BBMap, ValueMapT &GlobalMap) {
+ const StoreInst *Store, ValueMapT &BBMap, ValueMapT &GlobalMap,
+ LoopToScevMapT <S) {
const Value *Pointer = Store->getPointerOperand();
Value *NewPointer =
- generateLocationAccessed(Store, Pointer, BBMap, GlobalMap);
- Value *ValueOperand = getNewValue(Store->getValueOperand(), BBMap, GlobalMap);
+ generateLocationAccessed(Store, Pointer, BBMap, GlobalMap, LTS);
+ Value *ValueOperand = getNewValue(Store->getValueOperand(), BBMap, GlobalMap,
+ LTS);
return Builder.CreateStore(ValueOperand, NewPointer);
}
void BlockGenerator::copyInstruction(const Instruction *Inst, ValueMapT &BBMap,
- ValueMapT &GlobalMap) {
+ ValueMapT &GlobalMap,
+ LoopToScevMapT <S) {
// Terminator instructions control the control flow. They are explicitly
// expressed in the clast and do not need to be copied.
if (Inst->isTerminator())
return;
if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
- BBMap[Load] = generateScalarLoad(Load, BBMap, GlobalMap);
+ BBMap[Load] = generateScalarLoad(Load, BBMap, GlobalMap, LTS);
return;
}
if (const StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
- BBMap[Store] = generateScalarStore(Store, BBMap, GlobalMap);
+ BBMap[Store] = generateScalarStore(Store, BBMap, GlobalMap, LTS);
return;
}
- copyInstScalar(Inst, BBMap, GlobalMap);
+ copyInstScalar(Inst, BBMap, GlobalMap, LTS);
}
-void BlockGenerator::copyBB(ValueMapT &GlobalMap) {
+void BlockGenerator::copyBB(ValueMapT &GlobalMap, LoopToScevMapT <S) {
BasicBlock *BB = Statement.getBasicBlock();
BasicBlock *CopyBB =
SplitBlock(Builder.GetInsertBlock(), Builder.GetInsertPoint(), P);
for (BasicBlock::const_iterator II = BB->begin(), IE = BB->end(); II != IE;
++II)
- copyInstruction(II, BBMap, GlobalMap);
+ copyInstruction(II, BBMap, GlobalMap, LTS);
}
VectorBlockGenerator::VectorBlockGenerator(
- IRBuilder<> &B, VectorValueMapT &GlobalMaps, ScopStmt &Stmt,
- __isl_keep isl_map *Schedule, Pass *P)
- : BlockGenerator(B, Stmt, P), GlobalMaps(GlobalMaps), Schedule(Schedule) {
+ IRBuilder<> &B, VectorValueMapT &GlobalMaps, std::vector<LoopToScevMapT> &VLTS,
+ ScopStmt &Stmt, __isl_keep isl_map *Schedule, Pass *P)
+ : BlockGenerator(B, Stmt, P), GlobalMaps(GlobalMaps), VLTS(VLTS),
+ Schedule(Schedule) {
assert(GlobalMaps.size() > 1 && "Only one vector lane found");
assert(Schedule && "No statement domain provided");
}
for (int Lane = 0; Lane < Width; Lane++)
Vector = Builder.CreateInsertElement(
- Vector, getNewValue(Old, ScalarMaps[Lane], GlobalMaps[Lane]),
- Builder.getInt32(Lane));
+ Vector, getNewValue(Old, ScalarMaps[Lane], GlobalMaps[Lane],
+ VLTS[Lane]), Builder.getInt32(Lane));
VectorMap[Old] = Vector;
ValueMapT &BBMap) {
const Value *Pointer = Load->getPointerOperand();
Type *VectorPtrType = getVectorPtrTy(Pointer, getVectorWidth());
- Value *NewPointer = getNewValue(Pointer, BBMap, GlobalMaps[0]);
+ Value *NewPointer = getNewValue(Pointer, BBMap, GlobalMaps[0], VLTS[0]);
Value *VectorPtr =
Builder.CreateBitCast(NewPointer, VectorPtrType, "vector_ptr");
LoadInst *VecLoad =
ValueMapT &BBMap) {
const Value *Pointer = Load->getPointerOperand();
Type *VectorPtrType = getVectorPtrTy(Pointer, 1);
- Value *NewPointer = getNewValue(Pointer, BBMap, GlobalMaps[0]);
+ Value *NewPointer = getNewValue(Pointer, BBMap, GlobalMaps[0], VLTS[0]);
Value *VectorPtr = Builder.CreateBitCast(NewPointer, VectorPtrType,
Load->getName() + "_p_vec_p");
LoadInst *ScalarLoad =
Value *Vector = UndefValue::get(VectorType);
for (int i = 0; i < VectorWidth; i++) {
- Value *NewPointer = getNewValue(Pointer, ScalarMaps[i], GlobalMaps[i]);
+ Value *NewPointer = getNewValue(Pointer, ScalarMaps[i], GlobalMaps[i],
+ VLTS[i]);
Value *ScalarLoad =
Builder.CreateLoad(NewPointer, Load->getName() + "_p_scalar_");
Vector = Builder.CreateInsertElement(
!VectorType::isValidElementType(Load->getType())) {
for (int i = 0; i < getVectorWidth(); i++)
ScalarMaps[i][Load] =
- generateScalarLoad(Load, ScalarMaps[i], GlobalMaps[i]);
+ generateScalarLoad(Load, ScalarMaps[i], GlobalMaps[i], VLTS[i]);
return;
}
if (Access.isStrideOne(isl_map_copy(Schedule))) {
Type *VectorPtrType = getVectorPtrTy(Pointer, VectorWidth);
- Value *NewPointer = getNewValue(Pointer, ScalarMaps[0], GlobalMaps[0]);
+ Value *NewPointer = getNewValue(Pointer, ScalarMaps[0], GlobalMaps[0],
+ VLTS[0]);
Value *VectorPtr =
Builder.CreateBitCast(NewPointer, VectorPtrType, "vector_ptr");
} else {
for (unsigned i = 0; i < ScalarMaps.size(); i++) {
Value *Scalar = Builder.CreateExtractElement(Vector, Builder.getInt32(i));
- Value *NewPointer = getNewValue(Pointer, ScalarMaps[i], GlobalMaps[i]);
+ Value *NewPointer = getNewValue(Pointer, ScalarMaps[i], GlobalMaps[i],
+ VLTS[i]);
Builder.CreateStore(Scalar, NewPointer);
}
}
HasVectorOperand = extractScalarValues(Inst, VectorMap, ScalarMaps);
for (int VectorLane = 0; VectorLane < getVectorWidth(); VectorLane++)
- copyInstScalar(Inst, ScalarMaps[VectorLane], GlobalMaps[VectorLane]);
+ copyInstScalar(Inst, ScalarMaps[VectorLane], GlobalMaps[VectorLane],
+ VLTS[VectorLane]);
if (!VectorType::isValidElementType(Inst->getType()) || !HasVectorOperand)
return;
// Map the Values from the old code to their counterparts in the new code.
ValueMapT ValueMap;
+ // Map the loops from the old code to expressions function of the induction
+ // variables in the new code. For example, when the code generator produces
+ // this AST:
+ //
+ // for (int c1 = 0; c1 <= 1023; c1 += 1)
+ // for (int c2 = 0; c2 <= 1023; c2 += 1)
+ // Stmt(c2 + 3, c1);
+ //
+ // LoopToScev is a map associating:
+ // "outer loop in the old loop nest" -> SCEV("c2 + 3"),
+ // "inner loop in the old loop nest" -> SCEV("c1").
+ LoopToScevMapT LoopToScev;
+
// clastVars maps from the textual representation of a clast variable to its
// current *Value. clast variables are scheduling variables, original
// induction variables or parameters. They are used either in loop bounds or
void codegen(const clast_assignment *a, ScopStmt *Statement,
unsigned Dimension, int vectorDim,
- std::vector<ValueMapT> *VectorVMap = 0);
+ std::vector<ValueMapT> *VectorVMap = 0,
+ std::vector<LoopToScevMapT> *VLTS = 0);
void codegenSubstitutions(const clast_stmt *Assignment, ScopStmt *Statement,
int vectorDim = 0,
- std::vector<ValueMapT> *VectorVMap = 0);
+ std::vector<ValueMapT> *VectorVMap = 0,
+ std::vector<LoopToScevMapT> *VLTS = 0);
void codegen(const clast_user_stmt *u, std::vector<Value *> *IVS = NULL,
const char *iterator = NULL, isl_set *scatteringDomain = 0);
void ClastStmtCodeGen::codegen(const clast_assignment *A, ScopStmt *Stmt,
unsigned Dim, int VectorDim,
- std::vector<ValueMapT> *VectorVMap) {
+ std::vector<ValueMapT> *VectorVMap,
+ std::vector<LoopToScevMapT> *VLTS) {
const PHINode *PN;
Value *RHS;
if (VectorVMap)
(*VectorVMap)[VectorDim][PN] = RHS;
+ const llvm::SCEV *URHS = S->getSE()->getUnknown(RHS);
+ if (VLTS)
+ (*VLTS)[VectorDim][Stmt->getLoopForDimension(Dim)] = URHS;
+
ValueMap[PN] = RHS;
+ LoopToScev[Stmt->getLoopForDimension(Dim)] = URHS;
}
void ClastStmtCodeGen::codegenSubstitutions(
const clast_stmt *Assignment, ScopStmt *Statement, int vectorDim,
- std::vector<ValueMapT> *VectorVMap) {
+ std::vector<ValueMapT> *VectorVMap, std::vector<LoopToScevMapT> *VLTS) {
int Dimension = 0;
while (Assignment) {
assert(CLAST_STMT_IS_A(Assignment, stmt_ass) &&
"Substitions are expected to be assignments");
codegen((const clast_assignment *)Assignment, Statement, Dimension,
- vectorDim, VectorVMap);
+ vectorDim, VectorVMap, VLTS);
Assignment = Assignment->next;
Dimension++;
}
int VectorDimensions = IVS ? IVS->size() : 1;
if (VectorDimensions == 1) {
- BlockGenerator::generate(Builder, *Statement, ValueMap, P);
+ BlockGenerator::generate(Builder, *Statement, ValueMap, LoopToScev, P);
return;
}
VectorValueMapT VectorMap(VectorDimensions);
+ std::vector<LoopToScevMapT> VLTS(VectorDimensions);
if (IVS) {
assert(u->substitutions && "Substitutions expected!");
for (std::vector<Value *>::iterator II = IVS->begin(), IE = IVS->end();
II != IE; ++II) {
ClastVars[iterator] = *II;
- codegenSubstitutions(u->substitutions, Statement, i, &VectorMap);
+ codegenSubstitutions(u->substitutions, Statement, i, &VectorMap, &VLTS);
i++;
}
}
isl_map *Schedule = extractPartialSchedule(Statement, Domain);
- VectorBlockGenerator::generate(Builder, *Statement, VectorMap, Schedule, P);
+ VectorBlockGenerator::generate(Builder, *Statement, VectorMap, VLTS, Schedule,
+ P);
isl_map_free(Schedule);
}
void createForSequential(__isl_take isl_ast_node *For);
void createSubstitutions(__isl_take isl_pw_multi_aff *PMA,
__isl_take isl_ast_build *Context, ScopStmt *Stmt,
- ValueMapT &VMap);
+ ValueMapT &VMap, LoopToScevMapT <S);
void createSubstitutionsVector(
__isl_take isl_pw_multi_aff *PMA, __isl_take isl_ast_build *Context,
- ScopStmt *Stmt, VectorValueMapT &VMap, std::vector<Value *> &IVS,
- __isl_take isl_id *IteratorID);
+ ScopStmt *Stmt, VectorValueMapT &VMap, std::vector<LoopToScevMapT> &VLTS,
+ std::vector<Value *> &IVS, __isl_take isl_id *IteratorID);
void createIf(__isl_take isl_ast_node *If);
void createUserVector(
__isl_take isl_ast_node *User, std::vector<Value *> &IVS,
isl_id *Id = isl_pw_multi_aff_get_tuple_id(Info->PMA, isl_dim_out);
ScopStmt *Stmt = (ScopStmt *)isl_id_get_user(Id);
VectorValueMapT VectorMap(IVS.size());
+ std::vector<LoopToScevMapT> VLTS(IVS.size());
isl_union_set *Domain = isl_union_set_from_set(Stmt->getDomain());
Schedule = isl_union_map_intersect_domain(Schedule, Domain);
createSubstitutionsVector(isl_pw_multi_aff_copy(Info->PMA),
isl_ast_build_copy(Info->Context), Stmt, VectorMap,
- IVS, IteratorID);
- VectorBlockGenerator::generate(Builder, *Stmt, VectorMap, S, P);
+ VLTS, IVS, IteratorID);
+ VectorBlockGenerator::generate(Builder, *Stmt, VectorMap, VLTS, S, P);
isl_map_free(S);
isl_id_free(Annotation);
void IslNodeBuilder::createSubstitutions(__isl_take isl_pw_multi_aff *PMA,
__isl_take isl_ast_build *Context,
- ScopStmt *Stmt, ValueMapT &VMap) {
+ ScopStmt *Stmt, ValueMapT &VMap,
+ LoopToScevMapT <S) {
for (unsigned i = 0; i < isl_pw_multi_aff_dim(PMA, isl_dim_out); ++i) {
isl_pw_aff *Aff;
isl_ast_expr *Expr;
// (because we calculate a value of the original induction variable).
V = Builder.CreateIntCast(V, OldIV->getType(), true);
VMap[OldIV] = V;
+ ScalarEvolution *SE = Stmt->getParent()->getSE();
+ LTS[Stmt->getLoopForDimension(i)] = SE->getUnknown(V);
}
isl_pw_multi_aff_free(PMA);
void IslNodeBuilder::createSubstitutionsVector(
__isl_take isl_pw_multi_aff *PMA, __isl_take isl_ast_build *Context,
- ScopStmt *Stmt, VectorValueMapT &VMap, std::vector<Value *> &IVS,
- __isl_take isl_id *IteratorID) {
+ ScopStmt *Stmt, VectorValueMapT &VMap, std::vector<LoopToScevMapT> &VLTS,
+ std::vector<Value *> &IVS, __isl_take isl_id *IteratorID) {
int i = 0;
Value *OldValue = IDToValue[IteratorID];
II != IE; ++II) {
IDToValue[IteratorID] = *II;
createSubstitutions(isl_pw_multi_aff_copy(PMA), isl_ast_build_copy(Context),
- Stmt, VMap[i]);
+ Stmt, VMap[i], VLTS[i]);
i++;
}
void IslNodeBuilder::createUser(__isl_take isl_ast_node *User) {
ValueMapT VMap;
+ LoopToScevMapT LTS;
struct IslAstUser *Info;
isl_id *Annotation, *Id;
ScopStmt *Stmt;
Stmt = (ScopStmt *)isl_id_get_user(Id);
createSubstitutions(isl_pw_multi_aff_copy(Info->PMA),
- isl_ast_build_copy(Info->Context), Stmt, VMap);
+ isl_ast_build_copy(Info->Context), Stmt, VMap, LTS);
- BlockGenerator::generate(Builder, *Stmt, VMap, P);
+ BlockGenerator::generate(Builder, *Stmt, VMap, LTS, P);
isl_ast_node_free(User);
isl_id_free(Annotation);