1 //===- IslAst.cpp - isl code generator interface --------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // The isl code generator interface takes a Scop and generates a isl_ast. This
11 // ist_ast can either be returned directly or it can be pretty printed to
12 // stdout.
13 //
14 // A typical isl_ast output looks like this:
15 //
16 // for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) {
17 //   bb2(c2);
18 // }
19 //
20 //===----------------------------------------------------------------------===//
21 
22 #include "polly/CodeGen/IslAst.h"
23 
24 #ifdef ISL_CODEGEN_FOUND
25 #include "polly/LinkAllPasses.h"
26 #include "polly/ScopInfo.h"
27 
28 #define DEBUG_TYPE "polly-ast"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Support/Debug.h"
31 
32 #include "isl/union_map.h"
33 #include "isl/list.h"
34 #include "isl/ast.h"
35 #include "isl/ast_build.h"
36 #include "isl/set.h"
37 #include "isl/map.h"
38 #include "isl/aff.h"
39 
40 using namespace llvm;
41 using namespace polly;
42 
43 static cl::opt<bool>
44 UseContext("polly-ast-use-context", cl::desc("Use context"), cl::Hidden,
45            cl::init(false), cl::ZeroOrMore);
46 
47 namespace polly {
48 class IslAst {
49 public:
50   IslAst(Scop *Scop);
51 
52   ~IslAst();
53 
54   /// Print a source code representation of the program.
55   void pprint(llvm::raw_ostream &OS);
56 
57   __isl_give isl_ast_node *getAst();
58 
59 private:
60   Scop *S;
61   isl_ast_node *Root;
62 
63   __isl_give isl_union_map *getSchedule();
64 };
65 } // End namespace polly.
66 
67 
68 static void IslAstUserFree(void *User)
69 {
70   struct IslAstUser *UserStruct = (struct IslAstUser *) User;
71   isl_ast_build_free(UserStruct->Context);
72   isl_pw_multi_aff_free(UserStruct->PMA);
73   free(UserStruct);
74 }
75 
76 static __isl_give isl_ast_node *AtEachDomain(__isl_keep isl_ast_node *Node,
77        __isl_keep isl_ast_build *Context, void *User)
78 {
79   isl_map *Map;
80   struct IslAstUser *UserStruct;
81 
82   UserStruct = (struct IslAstUser *) malloc(sizeof(struct IslAstUser));
83 
84   Map = isl_map_from_union_map(isl_ast_build_get_schedule(Context));
85   UserStruct->PMA = isl_pw_multi_aff_from_map(isl_map_reverse(Map));
86   UserStruct->Context = isl_ast_build_copy(Context);
87 
88   isl_id *Annotation = isl_id_alloc(isl_ast_node_get_ctx(Node), NULL,
89                                     UserStruct);
90   Annotation = isl_id_set_free_user(Annotation, &IslAstUserFree);
91   return isl_ast_node_set_annotation(Node, Annotation);
92 }
93 
94 IslAst::IslAst(Scop *Scop) : S(Scop) {
95   isl_ctx *Ctx = S->getIslCtx();
96   isl_options_set_ast_build_atomic_upper_bound(Ctx, true);
97   isl_ast_build *Context;
98 
99   if (UseContext)
100     Context = isl_ast_build_from_context(S->getContext());
101   else
102     Context = isl_ast_build_from_context(isl_set_universe(S->getParamSpace()));
103 
104   Context = isl_ast_build_set_at_each_domain(Context, AtEachDomain, NULL);
105 
106   isl_union_map *Schedule = getSchedule();
107 
108   Function *F = Scop->getRegion().getEntry()->getParent();
109 
110   DEBUG(dbgs() << ":: isl ast :: " << F->getName()
111                << " :: " << Scop->getRegion().getNameStr() << "\n");;
112   DEBUG(dbgs() << S->getContextStr() << "\n";
113     isl_union_map_dump(Schedule);
114   );
115 
116   Root = isl_ast_build_ast_from_schedule(Context, Schedule);
117 
118   isl_ast_build_free(Context);
119 
120   DEBUG(pprint(dbgs()));
121 }
122 
123 __isl_give isl_union_map *IslAst::getSchedule() {
124   isl_union_map *Schedule = isl_union_map_empty(S->getParamSpace());
125 
126   for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
127     ScopStmt *Stmt = *SI;
128     isl_map *StmtSchedule = Stmt->getScattering();
129 
130     StmtSchedule = isl_map_intersect_domain(StmtSchedule, Stmt->getDomain());
131     Schedule = isl_union_map_union(Schedule,
132                                    isl_union_map_from_map(StmtSchedule));
133   }
134 
135   return Schedule;
136 }
137 
138 IslAst::~IslAst() {
139   isl_ast_node_free(Root);
140 }
141 
142 /// Print a C like representation of the program.
143 void IslAst::pprint(llvm::raw_ostream &OS) {
144   isl_ast_node *Root;
145   isl_ast_print_options *Options = isl_ast_print_options_alloc(S->getIslCtx());
146   isl_printer *P = isl_printer_to_str(S->getIslCtx());
147   P = isl_printer_set_output_format(P, ISL_FORMAT_C);
148   Root = getAst();
149   P = isl_ast_node_print(Root, P, Options);
150   char *result = isl_printer_get_str(P);
151   OS << result << "\n";
152   isl_printer_free(P);
153   isl_ast_node_free(Root);
154   isl_ast_print_options_free(Options);
155 }
156 
157 /// Create the isl_ast from this program.
158 __isl_give isl_ast_node *IslAst::getAst() {
159   return isl_ast_node_copy(Root);
160 }
161 
162 void IslAstInfo::pprint(llvm::raw_ostream &OS) {
163   Ast->pprint(OS);
164 }
165 
166 void IslAstInfo::releaseMemory() {
167   if (Ast) {
168     delete Ast;
169     Ast = 0;
170   }
171 }
172 
173 bool IslAstInfo::runOnScop(Scop &Scop) {
174   if (Ast)
175     delete Ast;
176 
177   S = &Scop;
178 
179   Ast = new IslAst(&Scop);
180 
181   return false;
182 }
183 
184 __isl_give isl_ast_node *IslAstInfo::getAst() {
185   return Ast->getAst();
186 }
187 
188 void IslAstInfo::printScop(raw_ostream &OS) const {
189   Function *F = S->getRegion().getEntry()->getParent();
190 
191   OS << "isl ast for function '" << F->getName() << "':\n";
192 
193   Ast->pprint(OS);
194 }
195 
196 void IslAstInfo::getAnalysisUsage(AnalysisUsage &AU) const {
197   // Get the Common analysis usage of ScopPasses.
198   ScopPass::getAnalysisUsage(AU);
199   AU.addRequired<ScopInfo>();
200 }
201 char IslAstInfo::ID = 0;
202 
203 INITIALIZE_PASS_BEGIN(IslAstInfo, "polly-ast",
204                       "Generate an AST of the SCoP (isl)", false, false)
205 INITIALIZE_PASS_DEPENDENCY(ScopInfo)
206 INITIALIZE_PASS_END(IslAstInfo, "polly-ast",
207                     "Generate an AST from the SCoP (isl)", false, false)
208 
209 Pass *polly::createIslAstInfoPass() {
210   return new IslAstInfo();
211 }
212 
213 #endif // CLOOG_FOUND
214