turn virtual scalars into virtual arrays
[pet.git] / scan.cc
blobb93c5dc0971c3a893f5835049e9a1dbf4071e266
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * Leiden University.
32 */
34 #include <set>
35 #include <map>
36 #include <iostream>
37 #include <clang/AST/ASTDiagnostic.h>
38 #include <clang/AST/Expr.h>
39 #include <clang/AST/RecursiveASTVisitor.h>
41 #include <isl/id.h>
42 #include <isl/space.h>
43 #include <isl/aff.h>
44 #include <isl/set.h>
46 #include "scan.h"
47 #include "scop.h"
48 #include "scop_plus.h"
50 #include "config.h"
52 using namespace std;
53 using namespace clang;
56 /* Look for any assignments to scalar variables in part of the parse
57 * tree and set assigned_value to NULL for each of them.
58 * Also reset assigned_value if the address of a scalar variable
59 * is being taken.
61 * This ensures that we won't use any previously stored value
62 * in the current subtree and its parents.
64 struct clear_assignments : RecursiveASTVisitor<clear_assignments> {
65 map<ValueDecl *, Expr *> &assigned_value;
67 clear_assignments(map<ValueDecl *, Expr *> &assigned_value) :
68 assigned_value(assigned_value) {}
70 bool VisitUnaryOperator(UnaryOperator *expr) {
71 Expr *arg;
72 DeclRefExpr *ref;
73 ValueDecl *decl;
75 if (expr->getOpcode() != UO_AddrOf)
76 return true;
78 arg = expr->getSubExpr();
79 if (arg->getStmtClass() != Stmt::DeclRefExprClass)
80 return true;
81 ref = cast<DeclRefExpr>(arg);
82 decl = ref->getDecl();
83 assigned_value[decl] = NULL;
84 return true;
87 bool VisitBinaryOperator(BinaryOperator *expr) {
88 Expr *lhs;
89 DeclRefExpr *ref;
90 ValueDecl *decl;
92 if (!expr->isAssignmentOp())
93 return true;
94 lhs = expr->getLHS();
95 if (lhs->getStmtClass() != Stmt::DeclRefExprClass)
96 return true;
97 ref = cast<DeclRefExpr>(lhs);
98 decl = ref->getDecl();
99 assigned_value[decl] = NULL;
100 return true;
104 /* Keep a copy of the currently assigned values.
106 * Any variable that is assigned a value inside the current scope
107 * is removed again when we leave the scope (either because it wasn't
108 * stored in the cache or because it has a different value in the cache).
110 struct assigned_value_cache {
111 map<ValueDecl *, Expr *> &assigned_value;
112 map<ValueDecl *, Expr *> cache;
114 assigned_value_cache(map<ValueDecl *, Expr *> &assigned_value) :
115 assigned_value(assigned_value), cache(assigned_value) {}
116 ~assigned_value_cache() {
117 map<ValueDecl *, Expr *>::iterator it = cache.begin();
118 for (it = assigned_value.begin(); it != assigned_value.end();
119 ++it) {
120 if (!it->second ||
121 (cache.find(it->first) != cache.end() &&
122 cache[it->first] != it->second))
123 cache[it->first] = NULL;
125 assigned_value = cache;
129 /* Called if we found something we (currently) cannot handle.
130 * We'll provide more informative warnings later.
132 * We only actually complain if autodetect is false.
134 void PetScan::unsupported(Stmt *stmt)
136 if (autodetect)
137 return;
139 SourceLocation loc = stmt->getLocStart();
140 DiagnosticsEngine &diag = PP.getDiagnostics();
141 unsigned id = diag.getCustomDiagID(DiagnosticsEngine::Warning,
142 "unsupported");
143 DiagnosticBuilder B = diag.Report(loc, id) << stmt->getSourceRange();
146 /* Extract an integer from "expr" and store it in "v".
148 int PetScan::extract_int(IntegerLiteral *expr, isl_int *v)
150 const Type *type = expr->getType().getTypePtr();
151 int is_signed = type->hasSignedIntegerRepresentation();
153 if (is_signed) {
154 int64_t i = expr->getValue().getSExtValue();
155 isl_int_set_si(*v, i);
156 } else {
157 uint64_t i = expr->getValue().getZExtValue();
158 isl_int_set_ui(*v, i);
161 return 0;
164 /* Extract an affine expression from the IntegerLiteral "expr".
166 __isl_give isl_pw_aff *PetScan::extract_affine(IntegerLiteral *expr)
168 isl_space *dim = isl_space_params_alloc(ctx, 0);
169 isl_local_space *ls = isl_local_space_from_space(isl_space_copy(dim));
170 isl_aff *aff = isl_aff_zero_on_domain(ls);
171 isl_set *dom = isl_set_universe(dim);
172 isl_int v;
174 isl_int_init(v);
175 extract_int(expr, &v);
176 aff = isl_aff_add_constant(aff, v);
177 isl_int_clear(v);
179 return isl_pw_aff_alloc(dom, aff);
182 /* Extract an affine expression from the APInt "val".
184 __isl_give isl_pw_aff *PetScan::extract_affine(const llvm::APInt &val)
186 isl_space *dim = isl_space_params_alloc(ctx, 0);
187 isl_local_space *ls = isl_local_space_from_space(isl_space_copy(dim));
188 isl_aff *aff = isl_aff_zero_on_domain(ls);
189 isl_set *dom = isl_set_universe(dim);
190 isl_int v;
192 isl_int_init(v);
193 isl_int_set_ui(v, val.getZExtValue());
194 aff = isl_aff_add_constant(aff, v);
195 isl_int_clear(v);
197 return isl_pw_aff_alloc(dom, aff);
200 __isl_give isl_pw_aff *PetScan::extract_affine(ImplicitCastExpr *expr)
202 return extract_affine(expr->getSubExpr());
205 /* Extract an affine expression from the DeclRefExpr "expr".
207 * If we have recorded an expression that was assigned to the variable
208 * before, then we convert this expressoin to an isl_pw_aff if it is
209 * affine and to an extra parameter otherwise (provided nesting_enabled is set).
211 * Otherwise, we simply return an expression that is equal
212 * to a parameter corresponding to the referenced variable.
214 __isl_give isl_pw_aff *PetScan::extract_affine(DeclRefExpr *expr)
216 ValueDecl *decl = expr->getDecl();
217 const Type *type = decl->getType().getTypePtr();
218 isl_id *id;
219 isl_space *dim;
220 isl_aff *aff;
221 isl_set *dom;
223 if (!type->isIntegerType()) {
224 unsupported(expr);
225 return NULL;
228 if (assigned_value.find(decl) != assigned_value.end() &&
229 assigned_value[decl] != NULL) {
230 if (is_affine(assigned_value[decl]))
231 return extract_affine(assigned_value[decl]);
232 else
233 return non_affine(expr);
236 id = isl_id_alloc(ctx, decl->getName().str().c_str(), decl);
237 dim = isl_space_params_alloc(ctx, 1);
239 dim = isl_space_set_dim_id(dim, isl_dim_param, 0, id);
241 dom = isl_set_universe(isl_space_copy(dim));
242 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
243 aff = isl_aff_add_coefficient_si(aff, isl_dim_param, 0, 1);
245 return isl_pw_aff_alloc(dom, aff);
248 /* Extract an affine expression from an integer division operation.
249 * In particular, if "expr" is lhs/rhs, then return
251 * lhs >= 0 ? floor(lhs/rhs) : ceil(lhs/rhs)
253 * The second argument (rhs) is required to be a (positive) integer constant.
255 __isl_give isl_pw_aff *PetScan::extract_affine_div(BinaryOperator *expr)
257 Expr *rhs_expr;
258 isl_pw_aff *lhs, *lhs_f, *lhs_c;
259 isl_pw_aff *res;
260 isl_int v;
261 isl_set *cond;
263 rhs_expr = expr->getRHS();
264 if (rhs_expr->getStmtClass() != Stmt::IntegerLiteralClass) {
265 unsupported(expr);
266 return NULL;
269 lhs = extract_affine(expr->getLHS());
270 cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(lhs));
272 isl_int_init(v);
273 extract_int(cast<IntegerLiteral>(rhs_expr), &v);
274 lhs = isl_pw_aff_scale_down(lhs, v);
275 isl_int_clear(v);
277 lhs_f = isl_pw_aff_floor(isl_pw_aff_copy(lhs));
278 lhs_c = isl_pw_aff_ceil(lhs);
279 res = isl_pw_aff_cond(cond, lhs_f, lhs_c);
281 return res;
284 /* Extract an affine expression from a modulo operation.
285 * In particular, if "expr" is lhs/rhs, then return
287 * lhs - rhs * (lhs >= 0 ? floor(lhs/rhs) : ceil(lhs/rhs))
289 * The second argument (rhs) is required to be a (positive) integer constant.
291 __isl_give isl_pw_aff *PetScan::extract_affine_mod(BinaryOperator *expr)
293 Expr *rhs_expr;
294 isl_pw_aff *lhs, *lhs_f, *lhs_c;
295 isl_pw_aff *res;
296 isl_int v;
297 isl_set *cond;
299 rhs_expr = expr->getRHS();
300 if (rhs_expr->getStmtClass() != Stmt::IntegerLiteralClass) {
301 unsupported(expr);
302 return NULL;
305 lhs = extract_affine(expr->getLHS());
306 cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(lhs));
308 isl_int_init(v);
309 extract_int(cast<IntegerLiteral>(rhs_expr), &v);
310 res = isl_pw_aff_scale_down(isl_pw_aff_copy(lhs), v);
312 lhs_f = isl_pw_aff_floor(isl_pw_aff_copy(res));
313 lhs_c = isl_pw_aff_ceil(res);
314 res = isl_pw_aff_cond(cond, lhs_f, lhs_c);
316 res = isl_pw_aff_scale(res, v);
317 isl_int_clear(v);
319 res = isl_pw_aff_sub(lhs, res);
321 return res;
324 /* Extract an affine expression from a multiplication operation.
325 * This is only allowed if at least one of the two arguments
326 * is a (piecewise) constant.
328 __isl_give isl_pw_aff *PetScan::extract_affine_mul(BinaryOperator *expr)
330 isl_pw_aff *lhs;
331 isl_pw_aff *rhs;
333 lhs = extract_affine(expr->getLHS());
334 rhs = extract_affine(expr->getRHS());
336 if (!isl_pw_aff_is_cst(lhs) && !isl_pw_aff_is_cst(rhs)) {
337 isl_pw_aff_free(lhs);
338 isl_pw_aff_free(rhs);
339 unsupported(expr);
340 return NULL;
343 return isl_pw_aff_mul(lhs, rhs);
346 /* Extract an affine expression from an addition or subtraction operation.
348 __isl_give isl_pw_aff *PetScan::extract_affine_add(BinaryOperator *expr)
350 isl_pw_aff *lhs;
351 isl_pw_aff *rhs;
353 lhs = extract_affine(expr->getLHS());
354 rhs = extract_affine(expr->getRHS());
356 switch (expr->getOpcode()) {
357 case BO_Add:
358 return isl_pw_aff_add(lhs, rhs);
359 case BO_Sub:
360 return isl_pw_aff_sub(lhs, rhs);
361 default:
362 isl_pw_aff_free(lhs);
363 isl_pw_aff_free(rhs);
364 return NULL;
369 /* Compute
371 * pwaff mod 2^width
373 static __isl_give isl_pw_aff *wrap(__isl_take isl_pw_aff *pwaff,
374 unsigned width)
376 isl_int mod;
378 isl_int_init(mod);
379 isl_int_set_si(mod, 1);
380 isl_int_mul_2exp(mod, mod, width);
382 pwaff = isl_pw_aff_mod(pwaff, mod);
384 isl_int_clear(mod);
386 return pwaff;
389 /* Extract an affine expression from some binary operations.
390 * If the result of the expression is unsigned, then we wrap it
391 * based on the size of the type.
393 __isl_give isl_pw_aff *PetScan::extract_affine(BinaryOperator *expr)
395 isl_pw_aff *res;
397 switch (expr->getOpcode()) {
398 case BO_Add:
399 case BO_Sub:
400 res = extract_affine_add(expr);
401 break;
402 case BO_Div:
403 res = extract_affine_div(expr);
404 break;
405 case BO_Rem:
406 res = extract_affine_mod(expr);
407 break;
408 case BO_Mul:
409 res = extract_affine_mul(expr);
410 break;
411 default:
412 unsupported(expr);
413 return NULL;
416 if (expr->getType()->isUnsignedIntegerType())
417 res = wrap(res, ast_context.getIntWidth(expr->getType()));
419 return res;
422 /* Extract an affine expression from a negation operation.
424 __isl_give isl_pw_aff *PetScan::extract_affine(UnaryOperator *expr)
426 if (expr->getOpcode() == UO_Minus)
427 return isl_pw_aff_neg(extract_affine(expr->getSubExpr()));
429 unsupported(expr);
430 return NULL;
433 __isl_give isl_pw_aff *PetScan::extract_affine(ParenExpr *expr)
435 return extract_affine(expr->getSubExpr());
438 /* Extract an affine expression from some special function calls.
439 * In particular, we handle "min", "max", "ceild" and "floord".
440 * In case of the latter two, the second argument needs to be
441 * a (positive) integer constant.
443 __isl_give isl_pw_aff *PetScan::extract_affine(CallExpr *expr)
445 FunctionDecl *fd;
446 string name;
447 isl_pw_aff *aff1, *aff2;
449 fd = expr->getDirectCallee();
450 if (!fd) {
451 unsupported(expr);
452 return NULL;
455 name = fd->getDeclName().getAsString();
456 if (!(expr->getNumArgs() == 2 && name == "min") &&
457 !(expr->getNumArgs() == 2 && name == "max") &&
458 !(expr->getNumArgs() == 2 && name == "floord") &&
459 !(expr->getNumArgs() == 2 && name == "ceild")) {
460 unsupported(expr);
461 return NULL;
464 if (name == "min" || name == "max") {
465 aff1 = extract_affine(expr->getArg(0));
466 aff2 = extract_affine(expr->getArg(1));
468 if (name == "min")
469 aff1 = isl_pw_aff_min(aff1, aff2);
470 else
471 aff1 = isl_pw_aff_max(aff1, aff2);
472 } else if (name == "floord" || name == "ceild") {
473 isl_int v;
474 Expr *arg2 = expr->getArg(1);
476 if (arg2->getStmtClass() != Stmt::IntegerLiteralClass) {
477 unsupported(expr);
478 return NULL;
480 aff1 = extract_affine(expr->getArg(0));
481 isl_int_init(v);
482 extract_int(cast<IntegerLiteral>(arg2), &v);
483 aff1 = isl_pw_aff_scale_down(aff1, v);
484 isl_int_clear(v);
485 if (name == "floord")
486 aff1 = isl_pw_aff_floor(aff1);
487 else
488 aff1 = isl_pw_aff_ceil(aff1);
489 } else {
490 unsupported(expr);
491 return NULL;
494 return aff1;
498 /* This method is called when we come across a non-affine expression.
499 * If nesting is allowed, we return a new parameter that corresponds
500 * to the non-affine expression. Otherwise, we simply complain.
502 * The new parameter is resolved in resolve_nested.
504 isl_pw_aff *PetScan::non_affine(Expr *expr)
506 isl_id *id;
507 isl_space *dim;
508 isl_aff *aff;
509 isl_set *dom;
511 if (!nesting_enabled) {
512 unsupported(expr);
513 return NULL;
516 id = isl_id_alloc(ctx, NULL, expr);
517 dim = isl_space_params_alloc(ctx, 1);
519 dim = isl_space_set_dim_id(dim, isl_dim_param, 0, id);
521 dom = isl_set_universe(isl_space_copy(dim));
522 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
523 aff = isl_aff_add_coefficient_si(aff, isl_dim_param, 0, 1);
525 return isl_pw_aff_alloc(dom, aff);
528 /* Affine expressions are not supposed to contain array accesses,
529 * but if nesting is allowed, we return a parameter corresponding
530 * to the array access.
532 __isl_give isl_pw_aff *PetScan::extract_affine(ArraySubscriptExpr *expr)
534 return non_affine(expr);
537 /* Extract an affine expression from a conditional operation.
539 __isl_give isl_pw_aff *PetScan::extract_affine(ConditionalOperator *expr)
541 isl_set *cond;
542 isl_pw_aff *lhs, *rhs;
544 cond = extract_condition(expr->getCond());
545 lhs = extract_affine(expr->getTrueExpr());
546 rhs = extract_affine(expr->getFalseExpr());
548 return isl_pw_aff_cond(cond, lhs, rhs);
551 /* Extract an affine expression, if possible, from "expr".
552 * Otherwise return NULL.
554 __isl_give isl_pw_aff *PetScan::extract_affine(Expr *expr)
556 switch (expr->getStmtClass()) {
557 case Stmt::ImplicitCastExprClass:
558 return extract_affine(cast<ImplicitCastExpr>(expr));
559 case Stmt::IntegerLiteralClass:
560 return extract_affine(cast<IntegerLiteral>(expr));
561 case Stmt::DeclRefExprClass:
562 return extract_affine(cast<DeclRefExpr>(expr));
563 case Stmt::BinaryOperatorClass:
564 return extract_affine(cast<BinaryOperator>(expr));
565 case Stmt::UnaryOperatorClass:
566 return extract_affine(cast<UnaryOperator>(expr));
567 case Stmt::ParenExprClass:
568 return extract_affine(cast<ParenExpr>(expr));
569 case Stmt::CallExprClass:
570 return extract_affine(cast<CallExpr>(expr));
571 case Stmt::ArraySubscriptExprClass:
572 return extract_affine(cast<ArraySubscriptExpr>(expr));
573 case Stmt::ConditionalOperatorClass:
574 return extract_affine(cast<ConditionalOperator>(expr));
575 default:
576 unsupported(expr);
578 return NULL;
581 __isl_give isl_map *PetScan::extract_access(ImplicitCastExpr *expr)
583 return extract_access(expr->getSubExpr());
586 /* Return the depth of an array of the given type.
588 static int array_depth(const Type *type)
590 if (type->isPointerType())
591 return 1 + array_depth(type->getPointeeType().getTypePtr());
592 if (type->isArrayType()) {
593 const ArrayType *atype;
594 type = type->getCanonicalTypeInternal().getTypePtr();
595 atype = cast<ArrayType>(type);
596 return 1 + array_depth(atype->getElementType().getTypePtr());
598 return 0;
601 /* Return the element type of the given array type.
603 static QualType base_type(QualType qt)
605 const Type *type = qt.getTypePtr();
607 if (type->isPointerType())
608 return base_type(type->getPointeeType());
609 if (type->isArrayType()) {
610 const ArrayType *atype;
611 type = type->getCanonicalTypeInternal().getTypePtr();
612 atype = cast<ArrayType>(type);
613 return base_type(atype->getElementType());
615 return qt;
618 /* Check if the element type corresponding to the given array type
619 * has a const qualifier.
621 static bool const_base(QualType qt)
623 const Type *type = qt.getTypePtr();
625 if (type->isPointerType())
626 return const_base(type->getPointeeType());
627 if (type->isArrayType()) {
628 const ArrayType *atype;
629 type = type->getCanonicalTypeInternal().getTypePtr();
630 atype = cast<ArrayType>(type);
631 return const_base(atype->getElementType());
634 return qt.isConstQualified();
637 /* Extract an access relation from a reference to a variable.
638 * If the variable has name "A" and its type corresponds to an
639 * array of depth d, then the returned access relation is of the
640 * form
642 * { [] -> A[i_1,...,i_d] }
644 __isl_give isl_map *PetScan::extract_access(DeclRefExpr *expr)
646 ValueDecl *decl = expr->getDecl();
647 int depth = array_depth(decl->getType().getTypePtr());
648 isl_id *id = isl_id_alloc(ctx, decl->getName().str().c_str(), decl);
649 isl_space *dim = isl_space_alloc(ctx, 0, 0, depth);
650 isl_map *access_rel;
652 dim = isl_space_set_tuple_id(dim, isl_dim_out, id);
654 access_rel = isl_map_universe(dim);
656 return access_rel;
659 /* Extract an access relation from an integer contant.
660 * If the value of the constant is "v", then the returned access relation
661 * is
663 * { [] -> [v] }
665 __isl_give isl_map *PetScan::extract_access(IntegerLiteral *expr)
667 return isl_map_from_range(isl_set_from_pw_aff(extract_affine(expr)));
670 /* Try and extract an access relation from the given Expr.
671 * Return NULL if it doesn't work out.
673 __isl_give isl_map *PetScan::extract_access(Expr *expr)
675 switch (expr->getStmtClass()) {
676 case Stmt::ImplicitCastExprClass:
677 return extract_access(cast<ImplicitCastExpr>(expr));
678 case Stmt::DeclRefExprClass:
679 return extract_access(cast<DeclRefExpr>(expr));
680 case Stmt::ArraySubscriptExprClass:
681 return extract_access(cast<ArraySubscriptExpr>(expr));
682 default:
683 unsupported(expr);
685 return NULL;
688 /* Assign the affine expression "index" to the output dimension "pos" of "map"
689 * and return the result.
691 __isl_give isl_map *set_index(__isl_take isl_map *map, int pos,
692 __isl_take isl_pw_aff *index)
694 isl_map *index_map;
695 int len = isl_map_dim(map, isl_dim_out);
696 isl_id *id;
698 index_map = isl_map_from_range(isl_set_from_pw_aff(index));
699 index_map = isl_map_insert_dims(index_map, isl_dim_out, 0, pos);
700 index_map = isl_map_add_dims(index_map, isl_dim_out, len - pos - 1);
701 id = isl_map_get_tuple_id(map, isl_dim_out);
702 index_map = isl_map_set_tuple_id(index_map, isl_dim_out, id);
704 map = isl_map_intersect(map, index_map);
706 return map;
709 /* Extract an access relation from the given array subscript expression.
710 * If nesting is allowed in general, then we turn it on while
711 * examining the index expression.
713 * We first extract an access relation from the base.
714 * This will result in an access relation with a range that corresponds
715 * to the array being accessed and with earlier indices filled in already.
716 * We then extract the current index and fill that in as well.
717 * The position of the current index is based on the type of base.
718 * If base is the actual array variable, then the depth of this type
719 * will be the same as the depth of the array and we will fill in
720 * the first array index.
721 * Otherwise, the depth of the base type will be smaller and we will fill
722 * in a later index.
724 __isl_give isl_map *PetScan::extract_access(ArraySubscriptExpr *expr)
726 Expr *base = expr->getBase();
727 Expr *idx = expr->getIdx();
728 isl_pw_aff *index;
729 isl_map *base_access;
730 isl_map *access;
731 int depth = array_depth(base->getType().getTypePtr());
732 int pos;
733 bool save_nesting = nesting_enabled;
735 nesting_enabled = allow_nested;
737 base_access = extract_access(base);
738 index = extract_affine(idx);
740 nesting_enabled = save_nesting;
742 pos = isl_map_dim(base_access, isl_dim_out) - depth;
743 access = set_index(base_access, pos, index);
745 return access;
748 /* Check if "expr" calls function "minmax" with two arguments and if so
749 * make lhs and rhs refer to these two arguments.
751 static bool is_minmax(Expr *expr, const char *minmax, Expr *&lhs, Expr *&rhs)
753 CallExpr *call;
754 FunctionDecl *fd;
755 string name;
757 if (expr->getStmtClass() != Stmt::CallExprClass)
758 return false;
760 call = cast<CallExpr>(expr);
761 fd = call->getDirectCallee();
762 if (!fd)
763 return false;
765 if (call->getNumArgs() != 2)
766 return false;
768 name = fd->getDeclName().getAsString();
769 if (name != minmax)
770 return false;
772 lhs = call->getArg(0);
773 rhs = call->getArg(1);
775 return true;
778 /* Check if "expr" is of the form min(lhs, rhs) and if so make
779 * lhs and rhs refer to the two arguments.
781 static bool is_min(Expr *expr, Expr *&lhs, Expr *&rhs)
783 return is_minmax(expr, "min", lhs, rhs);
786 /* Check if "expr" is of the form max(lhs, rhs) and if so make
787 * lhs and rhs refer to the two arguments.
789 static bool is_max(Expr *expr, Expr *&lhs, Expr *&rhs)
791 return is_minmax(expr, "max", lhs, rhs);
794 /* Extract a set of values satisfying the comparison "LHS op RHS"
795 * "comp" is the original statement that "LHS op RHS" is derived from
796 * and is used for diagnostics.
798 * If the comparison is of the form
800 * a <= min(b,c)
802 * then the set is constructed as the intersection of the set corresponding
803 * to the comparisons
805 * a <= b and a <= c
807 * A similar optimization is performed for max(a,b) <= c.
808 * We do this because that will lead to simpler representations of the set.
809 * If isl is ever enhanced to explicitly deal with min and max expressions,
810 * this optimization can be removed.
812 __isl_give isl_set *PetScan::extract_comparison(BinaryOperatorKind op,
813 Expr *LHS, Expr *RHS, Stmt *comp)
815 isl_pw_aff *lhs;
816 isl_pw_aff *rhs;
817 isl_set *cond;
819 if (op == BO_GT)
820 return extract_comparison(BO_LT, RHS, LHS, comp);
821 if (op == BO_GE)
822 return extract_comparison(BO_LE, RHS, LHS, comp);
824 if (op == BO_LT || op == BO_LE) {
825 Expr *expr1, *expr2;
826 isl_set *set1, *set2;
827 if (is_min(RHS, expr1, expr2)) {
828 set1 = extract_comparison(op, LHS, expr1, comp);
829 set2 = extract_comparison(op, LHS, expr2, comp);
830 return isl_set_intersect(set1, set2);
832 if (is_max(LHS, expr1, expr2)) {
833 set1 = extract_comparison(op, expr1, RHS, comp);
834 set2 = extract_comparison(op, expr2, RHS, comp);
835 return isl_set_intersect(set1, set2);
839 lhs = extract_affine(LHS);
840 rhs = extract_affine(RHS);
842 switch (op) {
843 case BO_LT:
844 cond = isl_pw_aff_lt_set(lhs, rhs);
845 break;
846 case BO_LE:
847 cond = isl_pw_aff_le_set(lhs, rhs);
848 break;
849 case BO_EQ:
850 cond = isl_pw_aff_eq_set(lhs, rhs);
851 break;
852 case BO_NE:
853 cond = isl_pw_aff_ne_set(lhs, rhs);
854 break;
855 default:
856 isl_pw_aff_free(lhs);
857 isl_pw_aff_free(rhs);
858 unsupported(comp);
859 return NULL;
862 cond = isl_set_coalesce(cond);
864 return cond;
867 __isl_give isl_set *PetScan::extract_comparison(BinaryOperator *comp)
869 return extract_comparison(comp->getOpcode(), comp->getLHS(),
870 comp->getRHS(), comp);
873 /* Extract a set of values satisfying the negation (logical not)
874 * of a subexpression.
876 __isl_give isl_set *PetScan::extract_boolean(UnaryOperator *op)
878 isl_set *cond;
880 cond = extract_condition(op->getSubExpr());
882 return isl_set_complement(cond);
885 /* Extract a set of values satisfying the union (logical or)
886 * or intersection (logical and) of two subexpressions.
888 __isl_give isl_set *PetScan::extract_boolean(BinaryOperator *comp)
890 isl_set *lhs;
891 isl_set *rhs;
892 isl_set *cond;
894 lhs = extract_condition(comp->getLHS());
895 rhs = extract_condition(comp->getRHS());
897 switch (comp->getOpcode()) {
898 case BO_LAnd:
899 cond = isl_set_intersect(lhs, rhs);
900 break;
901 case BO_LOr:
902 cond = isl_set_union(lhs, rhs);
903 break;
904 default:
905 isl_set_free(lhs);
906 isl_set_free(rhs);
907 unsupported(comp);
908 return NULL;
911 return cond;
914 __isl_give isl_set *PetScan::extract_condition(UnaryOperator *expr)
916 switch (expr->getOpcode()) {
917 case UO_LNot:
918 return extract_boolean(expr);
919 default:
920 unsupported(expr);
921 return NULL;
925 /* Extract a set of values satisfying the condition "expr != 0".
927 __isl_give isl_set *PetScan::extract_implicit_condition(Expr *expr)
929 return isl_pw_aff_non_zero_set(extract_affine(expr));
932 /* Extract a set of values satisfying the condition expressed by "expr".
934 * If the expression doesn't look like a condition, we assume it
935 * is an affine expression and return the condition "expr != 0".
937 __isl_give isl_set *PetScan::extract_condition(Expr *expr)
939 BinaryOperator *comp;
941 if (!expr)
942 return isl_set_universe(isl_space_params_alloc(ctx, 0));
944 if (expr->getStmtClass() == Stmt::ParenExprClass)
945 return extract_condition(cast<ParenExpr>(expr)->getSubExpr());
947 if (expr->getStmtClass() == Stmt::UnaryOperatorClass)
948 return extract_condition(cast<UnaryOperator>(expr));
950 if (expr->getStmtClass() != Stmt::BinaryOperatorClass)
951 return extract_implicit_condition(expr);
953 comp = cast<BinaryOperator>(expr);
954 switch (comp->getOpcode()) {
955 case BO_LT:
956 case BO_LE:
957 case BO_GT:
958 case BO_GE:
959 case BO_EQ:
960 case BO_NE:
961 return extract_comparison(comp);
962 case BO_LAnd:
963 case BO_LOr:
964 return extract_boolean(comp);
965 default:
966 return extract_implicit_condition(expr);
970 static enum pet_op_type UnaryOperatorKind2pet_op_type(UnaryOperatorKind kind)
972 switch (kind) {
973 case UO_Minus:
974 return pet_op_minus;
975 default:
976 return pet_op_last;
980 static enum pet_op_type BinaryOperatorKind2pet_op_type(BinaryOperatorKind kind)
982 switch (kind) {
983 case BO_AddAssign:
984 return pet_op_add_assign;
985 case BO_SubAssign:
986 return pet_op_sub_assign;
987 case BO_MulAssign:
988 return pet_op_mul_assign;
989 case BO_DivAssign:
990 return pet_op_div_assign;
991 case BO_Assign:
992 return pet_op_assign;
993 case BO_Add:
994 return pet_op_add;
995 case BO_Sub:
996 return pet_op_sub;
997 case BO_Mul:
998 return pet_op_mul;
999 case BO_Div:
1000 return pet_op_div;
1001 case BO_EQ:
1002 return pet_op_eq;
1003 case BO_LE:
1004 return pet_op_le;
1005 case BO_LT:
1006 return pet_op_lt;
1007 case BO_GT:
1008 return pet_op_gt;
1009 default:
1010 return pet_op_last;
1014 /* Construct a pet_expr representing a unary operator expression.
1016 struct pet_expr *PetScan::extract_expr(UnaryOperator *expr)
1018 struct pet_expr *arg;
1019 enum pet_op_type op;
1021 op = UnaryOperatorKind2pet_op_type(expr->getOpcode());
1022 if (op == pet_op_last) {
1023 unsupported(expr);
1024 return NULL;
1027 arg = extract_expr(expr->getSubExpr());
1029 return pet_expr_new_unary(ctx, op, arg);
1032 /* Mark the given access pet_expr as a write.
1033 * If a scalar is being accessed, then mark its value
1034 * as unknown in assigned_value.
1036 void PetScan::mark_write(struct pet_expr *access)
1038 isl_id *id;
1039 ValueDecl *decl;
1041 access->acc.write = 1;
1042 access->acc.read = 0;
1044 if (isl_map_dim(access->acc.access, isl_dim_out) != 0)
1045 return;
1047 id = isl_map_get_tuple_id(access->acc.access, isl_dim_out);
1048 decl = (ValueDecl *) isl_id_get_user(id);
1049 assigned_value[decl] = NULL;
1050 isl_id_free(id);
1053 /* Construct a pet_expr representing a binary operator expression.
1055 * If the top level operator is an assignment and the LHS is an access,
1056 * then we mark that access as a write. If the operator is a compound
1057 * assignment, the access is marked as both a read and a write.
1059 * If "expr" assigns something to a scalar variable, then we keep track
1060 * of the assigned expression in assigned_value so that we can plug
1061 * it in when we later come across the same variable.
1063 struct pet_expr *PetScan::extract_expr(BinaryOperator *expr)
1065 struct pet_expr *lhs, *rhs;
1066 enum pet_op_type op;
1068 op = BinaryOperatorKind2pet_op_type(expr->getOpcode());
1069 if (op == pet_op_last) {
1070 unsupported(expr);
1071 return NULL;
1074 lhs = extract_expr(expr->getLHS());
1075 rhs = extract_expr(expr->getRHS());
1077 if (expr->isAssignmentOp() && lhs && lhs->type == pet_expr_access) {
1078 mark_write(lhs);
1079 if (expr->isCompoundAssignmentOp())
1080 lhs->acc.read = 1;
1083 if (expr->getOpcode() == BO_Assign &&
1084 lhs && lhs->type == pet_expr_access &&
1085 isl_map_dim(lhs->acc.access, isl_dim_out) == 0) {
1086 isl_id *id = isl_map_get_tuple_id(lhs->acc.access, isl_dim_out);
1087 ValueDecl *decl = (ValueDecl *) isl_id_get_user(id);
1088 assigned_value[decl] = expr->getRHS();
1089 isl_id_free(id);
1092 return pet_expr_new_binary(ctx, op, lhs, rhs);
1095 /* Construct a pet_expr representing a conditional operation.
1097 struct pet_expr *PetScan::extract_expr(ConditionalOperator *expr)
1099 struct pet_expr *cond, *lhs, *rhs;
1101 cond = extract_expr(expr->getCond());
1102 lhs = extract_expr(expr->getTrueExpr());
1103 rhs = extract_expr(expr->getFalseExpr());
1105 return pet_expr_new_ternary(ctx, cond, lhs, rhs);
1108 struct pet_expr *PetScan::extract_expr(ImplicitCastExpr *expr)
1110 return extract_expr(expr->getSubExpr());
1113 /* Construct a pet_expr representing a floating point value.
1115 struct pet_expr *PetScan::extract_expr(FloatingLiteral *expr)
1117 return pet_expr_new_double(ctx, expr->getValueAsApproximateDouble());
1120 /* Extract an access relation from "expr" and then convert it into
1121 * a pet_expr.
1123 struct pet_expr *PetScan::extract_access_expr(Expr *expr)
1125 isl_map *access;
1126 struct pet_expr *pe;
1128 switch (expr->getStmtClass()) {
1129 case Stmt::ArraySubscriptExprClass:
1130 access = extract_access(cast<ArraySubscriptExpr>(expr));
1131 break;
1132 case Stmt::DeclRefExprClass:
1133 access = extract_access(cast<DeclRefExpr>(expr));
1134 break;
1135 case Stmt::IntegerLiteralClass:
1136 access = extract_access(cast<IntegerLiteral>(expr));
1137 break;
1138 default:
1139 unsupported(expr);
1140 return NULL;
1143 pe = pet_expr_from_access(access);
1145 return pe;
1148 struct pet_expr *PetScan::extract_expr(ParenExpr *expr)
1150 return extract_expr(expr->getSubExpr());
1153 /* Construct a pet_expr representing a function call.
1155 * If we are passing along a pointer to an array element
1156 * or an entire row or even higher dimensional slice of an array,
1157 * then the function being called may write into the array.
1159 * We assume here that if the function is declared to take a pointer
1160 * to a const type, then the function will perform a read
1161 * and that otherwise, it will perform a write.
1163 struct pet_expr *PetScan::extract_expr(CallExpr *expr)
1165 struct pet_expr *res = NULL;
1166 FunctionDecl *fd;
1167 string name;
1169 fd = expr->getDirectCallee();
1170 if (!fd) {
1171 unsupported(expr);
1172 return NULL;
1175 name = fd->getDeclName().getAsString();
1176 res = pet_expr_new_call(ctx, name.c_str(), expr->getNumArgs());
1177 if (!res)
1178 return NULL;
1180 for (int i = 0; i < expr->getNumArgs(); ++i) {
1181 Expr *arg = expr->getArg(i);
1182 int is_addr = 0;
1184 if (arg->getStmtClass() == Stmt::ImplicitCastExprClass) {
1185 ImplicitCastExpr *ice = cast<ImplicitCastExpr>(arg);
1186 arg = ice->getSubExpr();
1188 if (arg->getStmtClass() == Stmt::UnaryOperatorClass) {
1189 UnaryOperator *op = cast<UnaryOperator>(arg);
1190 if (op->getOpcode() == UO_AddrOf) {
1191 is_addr = 1;
1192 arg = op->getSubExpr();
1195 res->args[i] = PetScan::extract_expr(arg);
1196 if (!res->args[i])
1197 goto error;
1198 if (arg->getStmtClass() == Stmt::ArraySubscriptExprClass &&
1199 array_depth(arg->getType().getTypePtr()) > 0)
1200 is_addr = 1;
1201 if (is_addr && res->args[i]->type == pet_expr_access) {
1202 ParmVarDecl *parm = fd->getParamDecl(i);
1203 if (!const_base(parm->getType()))
1204 mark_write(res->args[i]);
1208 return res;
1209 error:
1210 pet_expr_free(res);
1211 return NULL;
1214 /* Try and onstruct a pet_expr representing "expr".
1216 struct pet_expr *PetScan::extract_expr(Expr *expr)
1218 switch (expr->getStmtClass()) {
1219 case Stmt::UnaryOperatorClass:
1220 return extract_expr(cast<UnaryOperator>(expr));
1221 case Stmt::CompoundAssignOperatorClass:
1222 case Stmt::BinaryOperatorClass:
1223 return extract_expr(cast<BinaryOperator>(expr));
1224 case Stmt::ImplicitCastExprClass:
1225 return extract_expr(cast<ImplicitCastExpr>(expr));
1226 case Stmt::ArraySubscriptExprClass:
1227 case Stmt::DeclRefExprClass:
1228 case Stmt::IntegerLiteralClass:
1229 return extract_access_expr(expr);
1230 case Stmt::FloatingLiteralClass:
1231 return extract_expr(cast<FloatingLiteral>(expr));
1232 case Stmt::ParenExprClass:
1233 return extract_expr(cast<ParenExpr>(expr));
1234 case Stmt::ConditionalOperatorClass:
1235 return extract_expr(cast<ConditionalOperator>(expr));
1236 case Stmt::CallExprClass:
1237 return extract_expr(cast<CallExpr>(expr));
1238 default:
1239 unsupported(expr);
1241 return NULL;
1244 /* Check if the given initialization statement is an assignment.
1245 * If so, return that assignment. Otherwise return NULL.
1247 BinaryOperator *PetScan::initialization_assignment(Stmt *init)
1249 BinaryOperator *ass;
1251 if (init->getStmtClass() != Stmt::BinaryOperatorClass)
1252 return NULL;
1254 ass = cast<BinaryOperator>(init);
1255 if (ass->getOpcode() != BO_Assign)
1256 return NULL;
1258 return ass;
1261 /* Check if the given initialization statement is a declaration
1262 * of a single variable.
1263 * If so, return that declaration. Otherwise return NULL.
1265 Decl *PetScan::initialization_declaration(Stmt *init)
1267 DeclStmt *decl;
1269 if (init->getStmtClass() != Stmt::DeclStmtClass)
1270 return NULL;
1272 decl = cast<DeclStmt>(init);
1274 if (!decl->isSingleDecl())
1275 return NULL;
1277 return decl->getSingleDecl();
1280 /* Given the assignment operator in the initialization of a for loop,
1281 * extract the induction variable, i.e., the (integer)variable being
1282 * assigned.
1284 ValueDecl *PetScan::extract_induction_variable(BinaryOperator *init)
1286 Expr *lhs;
1287 DeclRefExpr *ref;
1288 ValueDecl *decl;
1289 const Type *type;
1291 lhs = init->getLHS();
1292 if (lhs->getStmtClass() != Stmt::DeclRefExprClass) {
1293 unsupported(init);
1294 return NULL;
1297 ref = cast<DeclRefExpr>(lhs);
1298 decl = ref->getDecl();
1299 type = decl->getType().getTypePtr();
1301 if (!type->isIntegerType()) {
1302 unsupported(lhs);
1303 return NULL;
1306 return decl;
1309 /* Given the initialization statement of a for loop and the single
1310 * declaration in this initialization statement,
1311 * extract the induction variable, i.e., the (integer) variable being
1312 * declared.
1314 VarDecl *PetScan::extract_induction_variable(Stmt *init, Decl *decl)
1316 VarDecl *vd;
1318 vd = cast<VarDecl>(decl);
1320 const QualType type = vd->getType();
1321 if (!type->isIntegerType()) {
1322 unsupported(init);
1323 return NULL;
1326 if (!vd->getInit()) {
1327 unsupported(init);
1328 return NULL;
1331 return vd;
1334 /* Check that op is of the form iv++ or iv--.
1335 * "inc" is accordingly set to 1 or -1.
1337 bool PetScan::check_unary_increment(UnaryOperator *op, clang::ValueDecl *iv,
1338 isl_int &inc)
1340 Expr *sub;
1341 DeclRefExpr *ref;
1343 if (!op->isIncrementDecrementOp()) {
1344 unsupported(op);
1345 return false;
1348 if (op->isIncrementOp())
1349 isl_int_set_si(inc, 1);
1350 else
1351 isl_int_set_si(inc, -1);
1353 sub = op->getSubExpr();
1354 if (sub->getStmtClass() != Stmt::DeclRefExprClass) {
1355 unsupported(op);
1356 return false;
1359 ref = cast<DeclRefExpr>(sub);
1360 if (ref->getDecl() != iv) {
1361 unsupported(op);
1362 return false;
1365 return true;
1368 /* If the isl_pw_aff on which isl_pw_aff_foreach_piece is called
1369 * has a single constant expression on a universe domain, then
1370 * put this constant in *user.
1372 static int extract_cst(__isl_take isl_set *set, __isl_take isl_aff *aff,
1373 void *user)
1375 isl_int *inc = (isl_int *)user;
1376 int res = 0;
1378 if (!isl_set_plain_is_universe(set) || !isl_aff_is_cst(aff))
1379 res = -1;
1380 else
1381 isl_aff_get_constant(aff, inc);
1383 isl_set_free(set);
1384 isl_aff_free(aff);
1386 return res;
1389 /* Check if op is of the form
1391 * iv = iv + inc
1393 * with inc a constant and set "inc" accordingly.
1395 * We extract an affine expression from the RHS and the subtract iv.
1396 * The result should be a constant.
1398 bool PetScan::check_binary_increment(BinaryOperator *op, clang::ValueDecl *iv,
1399 isl_int &inc)
1401 Expr *lhs;
1402 DeclRefExpr *ref;
1403 isl_id *id;
1404 isl_space *dim;
1405 isl_aff *aff;
1406 isl_pw_aff *val;
1408 if (op->getOpcode() != BO_Assign) {
1409 unsupported(op);
1410 return false;
1413 lhs = op->getLHS();
1414 if (lhs->getStmtClass() != Stmt::DeclRefExprClass) {
1415 unsupported(op);
1416 return false;
1419 ref = cast<DeclRefExpr>(lhs);
1420 if (ref->getDecl() != iv) {
1421 unsupported(op);
1422 return false;
1425 val = extract_affine(op->getRHS());
1427 id = isl_id_alloc(ctx, iv->getName().str().c_str(), iv);
1429 dim = isl_space_params_alloc(ctx, 1);
1430 dim = isl_space_set_dim_id(dim, isl_dim_param, 0, id);
1431 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
1432 aff = isl_aff_add_coefficient_si(aff, isl_dim_param, 0, 1);
1434 val = isl_pw_aff_sub(val, isl_pw_aff_from_aff(aff));
1436 if (isl_pw_aff_foreach_piece(val, &extract_cst, &inc) < 0) {
1437 isl_pw_aff_free(val);
1438 unsupported(op);
1439 return false;
1442 isl_pw_aff_free(val);
1444 return true;
1447 /* Check that op is of the form iv += cst or iv -= cst.
1448 * "inc" is set to cst or -cst accordingly.
1450 bool PetScan::check_compound_increment(CompoundAssignOperator *op,
1451 clang::ValueDecl *iv, isl_int &inc)
1453 Expr *lhs, *rhs;
1454 DeclRefExpr *ref;
1455 bool neg = false;
1457 BinaryOperatorKind opcode;
1459 opcode = op->getOpcode();
1460 if (opcode != BO_AddAssign && opcode != BO_SubAssign) {
1461 unsupported(op);
1462 return false;
1464 if (opcode == BO_SubAssign)
1465 neg = true;
1467 lhs = op->getLHS();
1468 if (lhs->getStmtClass() != Stmt::DeclRefExprClass) {
1469 unsupported(op);
1470 return false;
1473 ref = cast<DeclRefExpr>(lhs);
1474 if (ref->getDecl() != iv) {
1475 unsupported(op);
1476 return false;
1479 rhs = op->getRHS();
1481 if (rhs->getStmtClass() == Stmt::UnaryOperatorClass) {
1482 UnaryOperator *op = cast<UnaryOperator>(rhs);
1483 if (op->getOpcode() != UO_Minus) {
1484 unsupported(op);
1485 return false;
1488 neg = !neg;
1490 rhs = op->getSubExpr();
1493 if (rhs->getStmtClass() != Stmt::IntegerLiteralClass) {
1494 unsupported(op);
1495 return false;
1498 extract_int(cast<IntegerLiteral>(rhs), &inc);
1499 if (neg)
1500 isl_int_neg(inc, inc);
1502 return true;
1505 /* Check that the increment of the given for loop increments
1506 * (or decrements) the induction variable "iv".
1507 * "up" is set to true if the induction variable is incremented.
1509 bool PetScan::check_increment(ForStmt *stmt, ValueDecl *iv, isl_int &v)
1511 Stmt *inc = stmt->getInc();
1513 if (!inc) {
1514 unsupported(stmt);
1515 return false;
1518 if (inc->getStmtClass() == Stmt::UnaryOperatorClass)
1519 return check_unary_increment(cast<UnaryOperator>(inc), iv, v);
1520 if (inc->getStmtClass() == Stmt::CompoundAssignOperatorClass)
1521 return check_compound_increment(
1522 cast<CompoundAssignOperator>(inc), iv, v);
1523 if (inc->getStmtClass() == Stmt::BinaryOperatorClass)
1524 return check_binary_increment(cast<BinaryOperator>(inc), iv, v);
1526 unsupported(inc);
1527 return false;
1530 /* Embed the given iteration domain in an extra outer loop
1531 * with induction variable "var".
1532 * If this variable appeared as a parameter in the constraints,
1533 * it is replaced by the new outermost dimension.
1535 static __isl_give isl_set *embed(__isl_take isl_set *set,
1536 __isl_take isl_id *var)
1538 int pos;
1540 set = isl_set_insert_dims(set, isl_dim_set, 0, 1);
1541 pos = isl_set_find_dim_by_id(set, isl_dim_param, var);
1542 if (pos >= 0) {
1543 set = isl_set_equate(set, isl_dim_param, pos, isl_dim_set, 0);
1544 set = isl_set_project_out(set, isl_dim_param, pos, 1);
1547 isl_id_free(var);
1548 return set;
1551 /* Construct a pet_scop for an infinite loop around the given body.
1553 * We extract a pet_scop for the body and then embed it in a loop with
1554 * iteration domain
1556 * { [t] : t >= 0 }
1558 * and schedule
1560 * { [t] -> [t] }
1562 struct pet_scop *PetScan::extract_infinite_loop(Stmt *body)
1564 isl_id *id;
1565 isl_space *dim;
1566 isl_set *domain;
1567 isl_map *sched;
1568 struct pet_scop *scop;
1570 scop = extract(body);
1571 if (!scop)
1572 return NULL;
1574 id = isl_id_alloc(ctx, "t", NULL);
1575 domain = isl_set_nat_universe(isl_space_set_alloc(ctx, 0, 1));
1576 domain = isl_set_set_dim_id(domain, isl_dim_set, 0, isl_id_copy(id));
1577 dim = isl_space_from_domain(isl_set_get_space(domain));
1578 dim = isl_space_add_dims(dim, isl_dim_out, 1);
1579 sched = isl_map_universe(dim);
1580 sched = isl_map_equate(sched, isl_dim_in, 0, isl_dim_out, 0);
1581 scop = pet_scop_embed(scop, domain, sched, id);
1583 return scop;
1586 /* Construct a pet_scop for an infinite loop, i.e., a loop of the form
1588 * for (;;)
1589 * body
1592 struct pet_scop *PetScan::extract_infinite_for(ForStmt *stmt)
1594 return extract_infinite_loop(stmt->getBody());
1597 /* Check if the while loop is of the form
1599 * while (1)
1600 * body
1602 * If so, construct a scop for an infinite loop around body.
1603 * Otherwise, fail.
1605 struct pet_scop *PetScan::extract(WhileStmt *stmt)
1607 Expr *cond;
1608 isl_set *set;
1609 int is_universe;
1611 cond = stmt->getCond();
1612 if (!cond) {
1613 unsupported(stmt);
1614 return NULL;
1617 set = extract_condition(cond);
1618 is_universe = isl_set_plain_is_universe(set);
1619 isl_set_free(set);
1621 if (!is_universe) {
1622 unsupported(stmt);
1623 return NULL;
1626 return extract_infinite_loop(stmt->getBody());
1629 /* Check whether "cond" expresses a simple loop bound
1630 * on the only set dimension.
1631 * In particular, if "up" is set then "cond" should contain only
1632 * upper bounds on the set dimension.
1633 * Otherwise, it should contain only lower bounds.
1635 static bool is_simple_bound(__isl_keep isl_set *cond, isl_int inc)
1637 if (isl_int_is_pos(inc))
1638 return !isl_set_dim_has_lower_bound(cond, isl_dim_set, 0);
1639 else
1640 return !isl_set_dim_has_upper_bound(cond, isl_dim_set, 0);
1643 /* Extend a condition on a given iteration of a loop to one that
1644 * imposes the same condition on all previous iterations.
1645 * "domain" expresses the lower [upper] bound on the iterations
1646 * when up is set [not set].
1648 * In particular, we construct the condition (when up is set)
1650 * forall i' : (domain(i') and i' <= i) => cond(i')
1652 * which is equivalent to
1654 * not exists i' : domain(i') and i' <= i and not cond(i')
1656 * We construct this set by negating cond, applying a map
1658 * { [i'] -> [i] : domain(i') and i' <= i }
1660 * and then negating the result again.
1662 static __isl_give isl_set *valid_for_each_iteration(__isl_take isl_set *cond,
1663 __isl_take isl_set *domain, isl_int inc)
1665 isl_map *previous_to_this;
1667 if (isl_int_is_pos(inc))
1668 previous_to_this = isl_map_lex_le(isl_set_get_space(domain));
1669 else
1670 previous_to_this = isl_map_lex_ge(isl_set_get_space(domain));
1672 previous_to_this = isl_map_intersect_domain(previous_to_this, domain);
1674 cond = isl_set_complement(cond);
1675 cond = isl_set_apply(cond, previous_to_this);
1676 cond = isl_set_complement(cond);
1678 return cond;
1681 /* Construct a domain of the form
1683 * [id] -> { [] : exists a: id = init + a * inc and a >= 0 }
1685 static __isl_give isl_set *strided_domain(__isl_take isl_id *id,
1686 __isl_take isl_pw_aff *init, isl_int inc)
1688 isl_aff *aff;
1689 isl_space *dim;
1690 isl_set *set;
1692 init = isl_pw_aff_insert_dims(init, isl_dim_in, 0, 1);
1693 dim = isl_pw_aff_get_domain_space(init);
1694 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
1695 aff = isl_aff_add_coefficient(aff, isl_dim_in, 0, inc);
1696 init = isl_pw_aff_add(init, isl_pw_aff_from_aff(aff));
1698 dim = isl_space_set_alloc(isl_pw_aff_get_ctx(init), 1, 1);
1699 dim = isl_space_set_dim_id(dim, isl_dim_param, 0, id);
1700 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
1701 aff = isl_aff_add_coefficient_si(aff, isl_dim_param, 0, 1);
1703 set = isl_pw_aff_eq_set(isl_pw_aff_from_aff(aff), init);
1705 set = isl_set_lower_bound_si(set, isl_dim_set, 0, 0);
1707 return isl_set_project_out(set, isl_dim_set, 0, 1);
1710 static unsigned get_type_size(ValueDecl *decl)
1712 return decl->getASTContext().getIntWidth(decl->getType());
1715 /* Assuming "cond" represents a simple bound on a loop where the loop
1716 * iterator "iv" is incremented (or decremented) by one, check if wrapping
1717 * is possible.
1719 * Under the given assumptions, wrapping is only possible if "cond" allows
1720 * for the last value before wrapping, i.e., 2^width - 1 in case of an
1721 * increasing iterator and 0 in case of a decreasing iterator.
1723 static bool can_wrap(__isl_keep isl_set *cond, ValueDecl *iv, isl_int inc)
1725 bool cw;
1726 isl_int limit;
1727 isl_set *test;
1729 test = isl_set_copy(cond);
1731 isl_int_init(limit);
1732 if (isl_int_is_neg(inc))
1733 isl_int_set_si(limit, 0);
1734 else {
1735 isl_int_set_si(limit, 1);
1736 isl_int_mul_2exp(limit, limit, get_type_size(iv));
1737 isl_int_sub_ui(limit, limit, 1);
1740 test = isl_set_fix(cond, isl_dim_set, 0, limit);
1741 cw = !isl_set_is_empty(test);
1742 isl_set_free(test);
1744 isl_int_clear(limit);
1746 return cw;
1749 /* Given a one-dimensional space, construct the following mapping on this
1750 * space
1752 * { [v] -> [v mod 2^width] }
1754 * where width is the number of bits used to represent the values
1755 * of the unsigned variable "iv".
1757 static __isl_give isl_map *compute_wrapping(__isl_take isl_space *dim,
1758 ValueDecl *iv)
1760 isl_int mod;
1761 isl_aff *aff;
1762 isl_map *map;
1764 isl_int_init(mod);
1765 isl_int_set_si(mod, 1);
1766 isl_int_mul_2exp(mod, mod, get_type_size(iv));
1768 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
1769 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, 0, 1);
1770 aff = isl_aff_mod(aff, mod);
1772 isl_int_clear(mod);
1774 return isl_map_from_basic_map(isl_basic_map_from_aff(aff));
1775 map = isl_map_reverse(map);
1778 /* Construct a pet_scop for a for statement.
1779 * The for loop is required to be of the form
1781 * for (i = init; condition; ++i)
1783 * or
1785 * for (i = init; condition; --i)
1787 * The initialization of the for loop should either be an assignment
1788 * to an integer variable, or a declaration of such a variable with
1789 * initialization.
1791 * We extract a pet_scop for the body and then embed it in a loop with
1792 * iteration domain and schedule
1794 * { [i] : i >= init and condition' }
1795 * { [i] -> [i] }
1797 * or
1799 * { [i] : i <= init and condition' }
1800 * { [i] -> [-i] }
1802 * Where condition' is equal to condition if the latter is
1803 * a simple upper [lower] bound and a condition that is extended
1804 * to apply to all previous iterations otherwise.
1806 * If the stride of the loop is not 1, then "i >= init" is replaced by
1808 * (exists a: i = init + stride * a and a >= 0)
1810 * If the loop iterator i is unsigned, then wrapping may occur.
1811 * During the computation, we work with a virtual iterator that
1812 * does not wrap. However, the condition in the code applies
1813 * to the wrapped value, so we need to change condition(i)
1814 * into condition([i % 2^width]).
1815 * After computing the virtual domain and schedule, we apply
1816 * the function { [v] -> [v % 2^width] } to the domain and the domain
1817 * of the schedule. In order not to lose any information, we also
1818 * need to intersect the domain of the schedule with the virtual domain
1819 * first, since some iterations in the wrapped domain may be scheduled
1820 * several times, typically an infinite number of times.
1821 * Note that there is no need to perform this final wrapping
1822 * if the loop condition (after wrapping) is simple.
1824 * Wrapping on unsigned iterators can be avoided entirely if
1825 * loop condition is simple, the loop iterator is incremented
1826 * [decremented] by one and the last value before wrapping cannot
1827 * possibly satisfy the loop condition.
1829 * Before extracting a pet_scop from the body we remove all
1830 * assignments in assigned_value to variables that are assigned
1831 * somewhere in the body of the loop.
1833 struct pet_scop *PetScan::extract_for(ForStmt *stmt)
1835 BinaryOperator *ass;
1836 Decl *decl;
1837 Stmt *init;
1838 Expr *lhs, *rhs;
1839 ValueDecl *iv;
1840 isl_space *dim;
1841 isl_set *domain;
1842 isl_map *sched;
1843 isl_set *cond;
1844 isl_id *id;
1845 struct pet_scop *scop;
1846 assigned_value_cache cache(assigned_value);
1847 isl_int inc;
1848 bool is_one;
1849 bool is_unsigned;
1850 bool is_simple;
1851 isl_map *wrap = NULL;
1853 if (!stmt->getInit() && !stmt->getCond() && !stmt->getInc())
1854 return extract_infinite_for(stmt);
1856 init = stmt->getInit();
1857 if (!init) {
1858 unsupported(stmt);
1859 return NULL;
1861 if ((ass = initialization_assignment(init)) != NULL) {
1862 iv = extract_induction_variable(ass);
1863 if (!iv)
1864 return NULL;
1865 lhs = ass->getLHS();
1866 rhs = ass->getRHS();
1867 } else if ((decl = initialization_declaration(init)) != NULL) {
1868 VarDecl *var = extract_induction_variable(init, decl);
1869 if (!var)
1870 return NULL;
1871 iv = var;
1872 rhs = var->getInit();
1873 lhs = DeclRefExpr::Create(iv->getASTContext(),
1874 var->getQualifierLoc(), iv, var->getInnerLocStart(),
1875 var->getType(), VK_LValue);
1876 } else {
1877 unsupported(stmt->getInit());
1878 return NULL;
1881 isl_int_init(inc);
1882 if (!check_increment(stmt, iv, inc)) {
1883 isl_int_clear(inc);
1884 return NULL;
1887 is_unsigned = iv->getType()->isUnsignedIntegerType();
1889 assigned_value[iv] = NULL;
1890 clear_assignments clear(assigned_value);
1891 clear.TraverseStmt(stmt->getBody());
1893 id = isl_id_alloc(ctx, iv->getName().str().c_str(), iv);
1895 is_one = isl_int_is_one(inc) || isl_int_is_negone(inc);
1896 if (is_one)
1897 domain = extract_comparison(isl_int_is_pos(inc) ? BO_GE : BO_LE,
1898 lhs, rhs, init);
1899 else {
1900 isl_pw_aff *lb = extract_affine(rhs);
1901 domain = strided_domain(isl_id_copy(id), lb, inc);
1904 cond = extract_condition(stmt->getCond());
1905 cond = embed(cond, isl_id_copy(id));
1906 domain = embed(domain, isl_id_copy(id));
1907 is_simple = is_simple_bound(cond, inc);
1908 if (is_unsigned &&
1909 (!is_simple || !is_one || can_wrap(cond, iv, inc))) {
1910 wrap = compute_wrapping(isl_set_get_space(cond), iv);
1911 cond = isl_set_apply(cond, isl_map_reverse(isl_map_copy(wrap)));
1912 is_simple = is_simple && is_simple_bound(cond, inc);
1914 if (!is_simple)
1915 cond = valid_for_each_iteration(cond,
1916 isl_set_copy(domain), inc);
1917 domain = isl_set_intersect(domain, cond);
1918 domain = isl_set_set_dim_id(domain, isl_dim_set, 0, isl_id_copy(id));
1919 dim = isl_space_from_domain(isl_set_get_space(domain));
1920 dim = isl_space_add_dims(dim, isl_dim_out, 1);
1921 sched = isl_map_universe(dim);
1922 if (isl_int_is_pos(inc))
1923 sched = isl_map_equate(sched, isl_dim_in, 0, isl_dim_out, 0);
1924 else
1925 sched = isl_map_oppose(sched, isl_dim_in, 0, isl_dim_out, 0);
1927 if (is_unsigned && !is_simple) {
1928 wrap = isl_map_set_dim_id(wrap,
1929 isl_dim_out, 0, isl_id_copy(id));
1930 sched = isl_map_intersect_domain(sched, isl_set_copy(domain));
1931 domain = isl_set_apply(domain, isl_map_copy(wrap));
1932 sched = isl_map_apply_domain(sched, wrap);
1933 } else
1934 isl_map_free(wrap);
1936 scop = extract(stmt->getBody());
1937 scop = pet_scop_embed(scop, domain, sched, id);
1939 isl_int_clear(inc);
1940 return scop;
1943 struct pet_scop *PetScan::extract(CompoundStmt *stmt)
1945 return extract(stmt->children());
1948 /* Look for parameters in any access relation in "expr" that
1949 * refer to non-affine constructs. In particular, these are
1950 * parameters with no name.
1952 * If there are any such parameters, then the domain of the access
1953 * relation, which is still [] at this point, is replaced by
1954 * [[] -> [t_1,...,t_n]], with n the number of these parameters
1955 * (after identifying identical non-affine constructs).
1956 * The parameters are then equated to the corresponding t dimensions
1957 * and subsequently projected out.
1958 * param2pos maps the position of the parameter to the position
1959 * of the corresponding t dimension.
1961 struct pet_expr *PetScan::resolve_nested(struct pet_expr *expr)
1963 int n;
1964 int nparam;
1965 int n_in;
1966 isl_space *dim;
1967 isl_map *map;
1968 std::map<int,int> param2pos;
1970 if (!expr)
1971 return expr;
1973 for (int i = 0; i < expr->n_arg; ++i) {
1974 expr->args[i] = resolve_nested(expr->args[i]);
1975 if (!expr->args[i]) {
1976 pet_expr_free(expr);
1977 return NULL;
1981 if (expr->type != pet_expr_access)
1982 return expr;
1984 nparam = isl_map_dim(expr->acc.access, isl_dim_param);
1985 n = 0;
1986 for (int i = 0; i < nparam; ++i) {
1987 isl_id *id = isl_map_get_dim_id(expr->acc.access,
1988 isl_dim_param, i);
1989 if (id && isl_id_get_user(id) && !isl_id_get_name(id))
1990 n++;
1991 isl_id_free(id);
1994 if (n == 0)
1995 return expr;
1997 expr->n_arg = n;
1998 expr->args = isl_calloc_array(ctx, struct pet_expr *, n);
1999 if (!expr->args)
2000 goto error;
2002 n_in = isl_map_dim(expr->acc.access, isl_dim_in);
2003 for (int i = 0, pos = 0; i < nparam; ++i) {
2004 int j;
2005 isl_id *id = isl_map_get_dim_id(expr->acc.access,
2006 isl_dim_param, i);
2007 Expr *nested;
2009 if (!(id && isl_id_get_user(id) && !isl_id_get_name(id))) {
2010 isl_id_free(id);
2011 continue;
2014 nested = (Expr *) isl_id_get_user(id);
2015 expr->args[pos] = extract_expr(nested);
2017 for (j = 0; j < pos; ++j)
2018 if (pet_expr_is_equal(expr->args[j], expr->args[pos]))
2019 break;
2021 if (j < pos) {
2022 pet_expr_free(expr->args[pos]);
2023 param2pos[i] = n_in + j;
2024 n--;
2025 } else
2026 param2pos[i] = n_in + pos++;
2028 isl_id_free(id);
2030 expr->n_arg = n;
2032 dim = isl_map_get_space(expr->acc.access);
2033 dim = isl_space_domain(dim);
2034 dim = isl_space_from_domain(dim);
2035 dim = isl_space_add_dims(dim, isl_dim_out, n);
2036 map = isl_map_universe(dim);
2037 map = isl_map_domain_map(map);
2038 map = isl_map_reverse(map);
2039 expr->acc.access = isl_map_apply_domain(expr->acc.access, map);
2041 for (int i = nparam - 1; i >= 0; --i) {
2042 isl_id *id = isl_map_get_dim_id(expr->acc.access,
2043 isl_dim_param, i);
2044 if (!(id && isl_id_get_user(id) && !isl_id_get_name(id))) {
2045 isl_id_free(id);
2046 continue;
2049 expr->acc.access = isl_map_equate(expr->acc.access,
2050 isl_dim_param, i, isl_dim_in,
2051 param2pos[i]);
2052 expr->acc.access = isl_map_project_out(expr->acc.access,
2053 isl_dim_param, i, 1);
2055 isl_id_free(id);
2058 return expr;
2059 error:
2060 pet_expr_free(expr);
2061 return NULL;
2064 /* Convert a top-level pet_expr to a pet_scop with one statement.
2065 * This mainly involves resolving nested expression parameters
2066 * and setting the name of the iteration space.
2067 * The name is given by "label" if it is non-NULL. Otherwise,
2068 * it is of the form S_<n_stmt>.
2070 struct pet_scop *PetScan::extract(Stmt *stmt, struct pet_expr *expr,
2071 __isl_take isl_id *label)
2073 struct pet_stmt *ps;
2074 SourceLocation loc = stmt->getLocStart();
2075 int line = PP.getSourceManager().getExpansionLineNumber(loc);
2077 expr = resolve_nested(expr);
2078 ps = pet_stmt_from_pet_expr(ctx, line, label, n_stmt++, expr);
2079 return pet_scop_from_pet_stmt(ctx, ps);
2082 /* Check whether "expr" is an affine expression.
2083 * We turn on autodetection so that we won't generate any warnings
2084 * and turn off nesting, so that we won't accept any non-affine constructs.
2086 bool PetScan::is_affine(Expr *expr)
2088 isl_pw_aff *pwaff;
2089 int save_autodetect = autodetect;
2090 bool save_nesting = nesting_enabled;
2092 autodetect = 1;
2093 nesting_enabled = false;
2095 pwaff = extract_affine(expr);
2096 isl_pw_aff_free(pwaff);
2098 autodetect = save_autodetect;
2099 nesting_enabled = save_nesting;
2101 return pwaff != NULL;
2104 /* Check whether "expr" is an affine constraint.
2105 * We turn on autodetection so that we won't generate any warnings
2106 * and turn off nesting, so that we won't accept any non-affine constructs.
2108 bool PetScan::is_affine_condition(Expr *expr)
2110 isl_set *set;
2111 int save_autodetect = autodetect;
2112 bool save_nesting = nesting_enabled;
2114 autodetect = 1;
2115 nesting_enabled = false;
2117 set = extract_condition(expr);
2118 isl_set_free(set);
2120 autodetect = save_autodetect;
2121 nesting_enabled = save_nesting;
2123 return set != NULL;
2126 /* If the top-level expression of "stmt" is an assignment, then
2127 * return that assignment as a BinaryOperator.
2128 * Otherwise return NULL.
2130 static BinaryOperator *top_assignment_or_null(Stmt *stmt)
2132 BinaryOperator *ass;
2134 if (!stmt)
2135 return NULL;
2136 if (stmt->getStmtClass() != Stmt::BinaryOperatorClass)
2137 return NULL;
2139 ass = cast<BinaryOperator>(stmt);
2140 if(ass->getOpcode() != BO_Assign)
2141 return NULL;
2143 return ass;
2146 /* Check if the given if statement is a conditional assignement
2147 * with a non-affine condition. If so, construct a pet_scop
2148 * corresponding to this conditional assignment. Otherwise return NULL.
2150 * In particular we check if "stmt" is of the form
2152 * if (condition)
2153 * a = f(...);
2154 * else
2155 * a = g(...);
2157 * where a is some array or scalar access.
2158 * The constructed pet_scop then corresponds to the expression
2160 * a = condition ? f(...) : g(...)
2162 * All access relations in f(...) are intersected with condition
2163 * while all access relation in g(...) are intersected with the complement.
2165 struct pet_scop *PetScan::extract_conditional_assignment(IfStmt *stmt)
2167 BinaryOperator *ass_then, *ass_else;
2168 isl_map *write_then, *write_else;
2169 isl_set *cond, *comp;
2170 isl_map *map, *map_true, *map_false;
2171 int equal;
2172 struct pet_expr *pe_cond, *pe_then, *pe_else, *pe, *pe_write;
2173 bool save_nesting = nesting_enabled;
2175 ass_then = top_assignment_or_null(stmt->getThen());
2176 ass_else = top_assignment_or_null(stmt->getElse());
2178 if (!ass_then || !ass_else)
2179 return NULL;
2181 if (is_affine_condition(stmt->getCond()))
2182 return NULL;
2184 write_then = extract_access(ass_then->getLHS());
2185 write_else = extract_access(ass_else->getLHS());
2187 equal = isl_map_is_equal(write_then, write_else);
2188 isl_map_free(write_else);
2189 if (equal < 0 || !equal) {
2190 isl_map_free(write_then);
2191 return NULL;
2194 nesting_enabled = allow_nested;
2195 cond = extract_condition(stmt->getCond());
2196 nesting_enabled = save_nesting;
2197 comp = isl_set_complement(isl_set_copy(cond));
2198 map_true = isl_map_from_domain(isl_set_from_params(isl_set_copy(cond)));
2199 map_true = isl_map_add_dims(map_true, isl_dim_out, 1);
2200 map_true = isl_map_fix_si(map_true, isl_dim_out, 0, 1);
2201 map_false = isl_map_from_domain(isl_set_from_params(isl_set_copy(comp)));
2202 map_false = isl_map_add_dims(map_false, isl_dim_out, 1);
2203 map_false = isl_map_fix_si(map_false, isl_dim_out, 0, 0);
2204 map = isl_map_union_disjoint(map_true, map_false);
2206 pe_cond = pet_expr_from_access(map);
2208 pe_then = extract_expr(ass_then->getRHS());
2209 pe_then = pet_expr_restrict(pe_then, cond);
2210 pe_else = extract_expr(ass_else->getRHS());
2211 pe_else = pet_expr_restrict(pe_else, comp);
2213 pe = pet_expr_new_ternary(ctx, pe_cond, pe_then, pe_else);
2214 pe_write = pet_expr_from_access(write_then);
2215 if (pe_write) {
2216 pe_write->acc.write = 1;
2217 pe_write->acc.read = 0;
2219 pe = pet_expr_new_binary(ctx, pet_op_assign, pe_write, pe);
2220 return extract(stmt, pe);
2223 /* Create an access to a virtual array representing the result
2224 * of a condition.
2225 * Unlike other accessed data, the id of the array is NULL as
2226 * there is no ValueDecl in the program corresponding to the virtual
2227 * array.
2228 * The array starts out as a scalar, but grows along with the
2229 * statement writing to the array in pet_scop_embed.
2231 static __isl_give isl_map *create_test_access(isl_ctx *ctx, int test_nr)
2233 isl_space *dim = isl_space_alloc(ctx, 0, 0, 0);
2234 isl_id *id;
2235 char name[50];
2237 snprintf(name, sizeof(name), "__pet_test_%d", test_nr);
2238 id = isl_id_alloc(ctx, name, NULL);
2239 dim = isl_space_set_tuple_id(dim, isl_dim_out, id);
2240 return isl_map_universe(dim);
2243 /* Create a pet_scop with a single statement evaluating "cond"
2244 * and writing the result to a virtual scalar, as expressed by
2245 * "access".
2247 struct pet_scop *PetScan::extract_non_affine_condition(Expr *cond,
2248 __isl_take isl_map *access)
2250 struct pet_expr *expr, *write;
2251 struct pet_stmt *ps;
2252 SourceLocation loc = cond->getLocStart();
2253 int line = PP.getSourceManager().getExpansionLineNumber(loc);
2255 write = pet_expr_from_access(access);
2256 if (write) {
2257 write->acc.write = 1;
2258 write->acc.read = 0;
2260 expr = extract_expr(cond);
2261 expr = pet_expr_new_binary(ctx, pet_op_assign, write, expr);
2262 ps = pet_stmt_from_pet_expr(ctx, line, NULL, n_stmt++, expr);
2263 return pet_scop_from_pet_stmt(ctx, ps);
2266 /* Add an array with the given extend ("access") to the list
2267 * of arrays in "scop" and return the extended pet_scop.
2268 * The array is marked as attaining values 0 and 1 only.
2270 static struct pet_scop *scop_add_array(struct pet_scop *scop,
2271 __isl_keep isl_map *access)
2273 isl_ctx *ctx = isl_map_get_ctx(access);
2274 isl_space *dim;
2275 struct pet_array **arrays;
2276 struct pet_array *array;
2278 if (!scop)
2279 return NULL;
2280 if (!ctx)
2281 goto error;
2283 arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
2284 scop->n_array + 1);
2285 if (!arrays)
2286 goto error;
2287 scop->arrays = arrays;
2289 array = isl_calloc_type(ctx, struct pet_array);
2290 if (!array)
2291 goto error;
2293 array->extent = isl_map_range(isl_map_copy(access));
2294 dim = isl_space_params_alloc(ctx, 0);
2295 array->context = isl_set_universe(dim);
2296 dim = isl_space_set_alloc(ctx, 0, 1);
2297 array->value_bounds = isl_set_universe(dim);
2298 array->value_bounds = isl_set_lower_bound_si(array->value_bounds,
2299 isl_dim_set, 0, 0);
2300 array->value_bounds = isl_set_upper_bound_si(array->value_bounds,
2301 isl_dim_set, 0, 1);
2302 array->element_type = strdup("int");
2304 scop->arrays[scop->n_array] = array;
2305 scop->n_array++;
2307 if (!array->extent || !array->context)
2308 goto error;
2310 return scop;
2311 error:
2312 pet_scop_free(scop);
2313 return NULL;
2316 /* Construct a pet_scop for an if statement.
2318 * If the condition fits the pattern of a conditional assignment,
2319 * then it is handled by extract_conditional_assignment.
2320 * Otherwise, we do the following.
2322 * If the condition is affine, then the condition is added
2323 * to the iteration domains of the then branch, while the
2324 * opposite of the condition in added to the iteration domains
2325 * of the else branch, if any.
2327 * If the condition is not-affine, then we create a separate
2328 * statement that write the result of the condition to a virtual scalar.
2329 * A constraint requiring the value of this virtual scalar to be one
2330 * is added to the iteration domains of the then branch.
2331 * Similarly, a constraint requiring the value of this virtual scalar
2332 * to be zero is added to the iteration domains of the else branch, if any.
2333 * We adjust the schedules to ensure that the virtual scalar is written
2334 * before it is read.
2336 struct pet_scop *PetScan::extract(IfStmt *stmt)
2338 struct pet_scop *scop_then, *scop_else, *scop;
2339 assigned_value_cache cache(assigned_value);
2340 isl_map *test_access = NULL;
2342 scop = extract_conditional_assignment(stmt);
2343 if (scop)
2344 return scop;
2346 if (allow_nested && !is_affine_condition(stmt->getCond())) {
2347 test_access = create_test_access(ctx, n_test++);
2348 scop = extract_non_affine_condition(stmt->getCond(),
2349 isl_map_copy(test_access));
2350 scop = scop_add_array(scop, test_access);
2351 if (!scop) {
2352 isl_map_free(test_access);
2353 return NULL;
2357 scop_then = extract(stmt->getThen());
2359 if (stmt->getElse()) {
2360 scop_else = extract(stmt->getElse());
2361 if (autodetect) {
2362 if (scop_then && !scop_else) {
2363 partial = true;
2364 pet_scop_free(scop);
2365 isl_map_free(test_access);
2366 return scop_then;
2368 if (!scop_then && scop_else) {
2369 partial = true;
2370 pet_scop_free(scop);
2371 isl_map_free(test_access);
2372 return scop_else;
2377 if (!scop) {
2378 isl_set *cond;
2379 cond = extract_condition(stmt->getCond());
2380 scop = pet_scop_restrict(scop_then, isl_set_copy(cond));
2382 if (stmt->getElse()) {
2383 cond = isl_set_complement(cond);
2384 scop_else = pet_scop_restrict(scop_else, cond);
2385 scop = pet_scop_add(ctx, scop, scop_else);
2386 } else
2387 isl_set_free(cond);
2388 } else {
2389 scop = pet_scop_prefix(scop, 0);
2390 scop_then = pet_scop_prefix(scop_then, 1);
2391 scop_then = pet_scop_filter(scop_then,
2392 isl_map_copy(test_access), 1);
2393 scop = pet_scop_add(ctx, scop, scop_then);
2394 if (stmt->getElse()) {
2395 scop_else = pet_scop_prefix(scop_else, 1);
2396 scop_else = pet_scop_filter(scop_else, test_access, 0);
2397 scop = pet_scop_add(ctx, scop, scop_else);
2398 } else
2399 isl_map_free(test_access);
2402 return scop;
2405 /* Try and construct a pet_scop for a label statement.
2406 * We currently only allow labels on expression statements.
2408 struct pet_scop *PetScan::extract(LabelStmt *stmt)
2410 isl_id *label;
2411 Stmt *sub;
2413 sub = stmt->getSubStmt();
2414 if (!isa<Expr>(sub)) {
2415 unsupported(stmt);
2416 return NULL;
2419 label = isl_id_alloc(ctx, stmt->getName(), NULL);
2421 return extract(sub, extract_expr(cast<Expr>(sub)), label);
2424 /* Try and construct a pet_scop corresponding to "stmt".
2426 struct pet_scop *PetScan::extract(Stmt *stmt)
2428 if (isa<Expr>(stmt))
2429 return extract(stmt, extract_expr(cast<Expr>(stmt)));
2431 switch (stmt->getStmtClass()) {
2432 case Stmt::WhileStmtClass:
2433 return extract(cast<WhileStmt>(stmt));
2434 case Stmt::ForStmtClass:
2435 return extract_for(cast<ForStmt>(stmt));
2436 case Stmt::IfStmtClass:
2437 return extract(cast<IfStmt>(stmt));
2438 case Stmt::CompoundStmtClass:
2439 return extract(cast<CompoundStmt>(stmt));
2440 case Stmt::LabelStmtClass:
2441 return extract(cast<LabelStmt>(stmt));
2442 default:
2443 unsupported(stmt);
2446 return NULL;
2449 /* Try and construct a pet_scop corresponding to (part of)
2450 * a sequence of statements.
2452 struct pet_scop *PetScan::extract(StmtRange stmt_range)
2454 pet_scop *scop;
2455 StmtIterator i;
2456 int j;
2457 bool partial_range = false;
2459 scop = pet_scop_empty(ctx);
2460 for (i = stmt_range.first, j = 0; i != stmt_range.second; ++i, ++j) {
2461 Stmt *child = *i;
2462 struct pet_scop *scop_i;
2463 scop_i = extract(child);
2464 if (scop && partial) {
2465 pet_scop_free(scop_i);
2466 break;
2468 scop_i = pet_scop_prefix(scop_i, j);
2469 if (autodetect) {
2470 if (scop_i)
2471 scop = pet_scop_add(ctx, scop, scop_i);
2472 else
2473 partial_range = true;
2474 if (scop->n_stmt != 0 && !scop_i)
2475 partial = true;
2476 } else {
2477 scop = pet_scop_add(ctx, scop, scop_i);
2479 if (partial)
2480 break;
2483 if (scop && partial_range)
2484 partial = true;
2486 return scop;
2489 /* Check if the scop marked by the user is exactly this Stmt
2490 * or part of this Stmt.
2491 * If so, return a pet_scop corresponding to the marked region.
2492 * Otherwise, return NULL.
2494 struct pet_scop *PetScan::scan(Stmt *stmt)
2496 SourceManager &SM = PP.getSourceManager();
2497 unsigned start_off, end_off;
2499 start_off = SM.getFileOffset(stmt->getLocStart());
2500 end_off = SM.getFileOffset(stmt->getLocEnd());
2502 if (start_off > loc.end)
2503 return NULL;
2504 if (end_off < loc.start)
2505 return NULL;
2506 if (start_off >= loc.start && end_off <= loc.end) {
2507 return extract(stmt);
2510 StmtIterator start;
2511 for (start = stmt->child_begin(); start != stmt->child_end(); ++start) {
2512 Stmt *child = *start;
2513 if (!child)
2514 continue;
2515 start_off = SM.getFileOffset(child->getLocStart());
2516 end_off = SM.getFileOffset(child->getLocEnd());
2517 if (start_off < loc.start && end_off > loc.end)
2518 return scan(child);
2519 if (start_off >= loc.start)
2520 break;
2523 StmtIterator end;
2524 for (end = start; end != stmt->child_end(); ++end) {
2525 Stmt *child = *end;
2526 start_off = SM.getFileOffset(child->getLocStart());
2527 if (start_off >= loc.end)
2528 break;
2531 return extract(StmtRange(start, end));
2534 /* Set the size of index "pos" of "array" to "size".
2535 * In particular, add a constraint of the form
2537 * i_pos < size
2539 * to array->extent and a constraint of the form
2541 * size >= 0
2543 * to array->context.
2545 static struct pet_array *update_size(struct pet_array *array, int pos,
2546 __isl_take isl_pw_aff *size)
2548 isl_set *valid;
2549 isl_set *univ;
2550 isl_set *bound;
2551 isl_space *dim;
2552 isl_aff *aff;
2553 isl_pw_aff *index;
2554 isl_id *id;
2556 valid = isl_pw_aff_nonneg_set(isl_pw_aff_copy(size));
2557 array->context = isl_set_intersect(array->context, valid);
2559 dim = isl_set_get_space(array->extent);
2560 aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
2561 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, pos, 1);
2562 univ = isl_set_universe(isl_aff_get_domain_space(aff));
2563 index = isl_pw_aff_alloc(univ, aff);
2565 size = isl_pw_aff_add_dims(size, isl_dim_in,
2566 isl_set_dim(array->extent, isl_dim_set));
2567 id = isl_set_get_tuple_id(array->extent);
2568 size = isl_pw_aff_set_tuple_id(size, isl_dim_in, id);
2569 bound = isl_pw_aff_lt_set(index, size);
2571 array->extent = isl_set_intersect(array->extent, bound);
2573 if (!array->context || !array->extent)
2574 goto error;
2576 return array;
2577 error:
2578 pet_array_free(array);
2579 return NULL;
2582 /* Figure out the size of the array at position "pos" and all
2583 * subsequent positions from "type" and update "array" accordingly.
2585 struct pet_array *PetScan::set_upper_bounds(struct pet_array *array,
2586 const Type *type, int pos)
2588 const ArrayType *atype;
2589 isl_pw_aff *size;
2591 if (!array)
2592 return NULL;
2594 if (type->isPointerType()) {
2595 type = type->getPointeeType().getTypePtr();
2596 return set_upper_bounds(array, type, pos + 1);
2598 if (!type->isArrayType())
2599 return array;
2601 type = type->getCanonicalTypeInternal().getTypePtr();
2602 atype = cast<ArrayType>(type);
2604 if (type->isConstantArrayType()) {
2605 const ConstantArrayType *ca = cast<ConstantArrayType>(atype);
2606 size = extract_affine(ca->getSize());
2607 array = update_size(array, pos, size);
2608 } else if (type->isVariableArrayType()) {
2609 const VariableArrayType *vla = cast<VariableArrayType>(atype);
2610 size = extract_affine(vla->getSizeExpr());
2611 array = update_size(array, pos, size);
2614 type = atype->getElementType().getTypePtr();
2616 return set_upper_bounds(array, type, pos + 1);
2619 /* Construct and return a pet_array corresponding to the variable "decl".
2620 * In particular, initialize array->extent to
2622 * { name[i_1,...,i_d] : i_1,...,i_d >= 0 }
2624 * and then call set_upper_bounds to set the upper bounds on the indices
2625 * based on the type of the variable.
2627 struct pet_array *PetScan::extract_array(isl_ctx *ctx, ValueDecl *decl)
2629 struct pet_array *array;
2630 QualType qt = decl->getType();
2631 const Type *type = qt.getTypePtr();
2632 int depth = array_depth(type);
2633 QualType base = base_type(qt);
2634 string name;
2635 isl_id *id;
2636 isl_space *dim;
2638 array = isl_calloc_type(ctx, struct pet_array);
2639 if (!array)
2640 return NULL;
2642 id = isl_id_alloc(ctx, decl->getName().str().c_str(), decl);
2643 dim = isl_space_set_alloc(ctx, 0, depth);
2644 dim = isl_space_set_tuple_id(dim, isl_dim_set, id);
2646 array->extent = isl_set_nat_universe(dim);
2648 dim = isl_space_params_alloc(ctx, 0);
2649 array->context = isl_set_universe(dim);
2651 array = set_upper_bounds(array, type, 0);
2652 if (!array)
2653 return NULL;
2655 name = base.getAsString();
2656 array->element_type = strdup(name.c_str());
2658 return array;
2661 /* Construct a list of pet_arrays, one for each array (or scalar)
2662 * accessed inside "scop" add this list to "scop" and return the result.
2664 * The context of "scop" is updated with the intesection of
2665 * the contexts of all arrays, i.e., constraints on the parameters
2666 * that ensure that the arrays have a valid (non-negative) size.
2668 struct pet_scop *PetScan::scan_arrays(struct pet_scop *scop)
2670 int i;
2671 set<ValueDecl *> arrays;
2672 set<ValueDecl *>::iterator it;
2673 int n_array;
2674 struct pet_array **scop_arrays;
2676 if (!scop)
2677 return NULL;
2679 pet_scop_collect_arrays(scop, arrays);
2680 if (arrays.size() == 0)
2681 return scop;
2683 n_array = scop->n_array;
2685 scop_arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
2686 n_array + arrays.size());
2687 if (!scop_arrays)
2688 goto error;
2689 scop->arrays = scop_arrays;
2691 for (it = arrays.begin(), i = 0; it != arrays.end(); ++it, ++i) {
2692 struct pet_array *array;
2693 scop->arrays[n_array + i] = array = extract_array(ctx, *it);
2694 if (!scop->arrays[n_array + i])
2695 goto error;
2696 scop->n_array++;
2697 scop->context = isl_set_intersect(scop->context,
2698 isl_set_copy(array->context));
2699 if (!scop->context)
2700 goto error;
2703 return scop;
2704 error:
2705 pet_scop_free(scop);
2706 return NULL;
2709 /* Construct a pet_scop from the given function.
2711 struct pet_scop *PetScan::scan(FunctionDecl *fd)
2713 pet_scop *scop;
2714 Stmt *stmt;
2716 stmt = fd->getBody();
2718 if (autodetect)
2719 scop = extract(stmt);
2720 else
2721 scop = scan(stmt);
2722 scop = pet_scop_detect_parameter_accesses(scop);
2723 scop = scan_arrays(scop);
2725 return scop;