pet.cc: pet_transform: handle NULL input
[pet.git] / inliner.cc
blob044fe3bacc15be527adfc24b42e995784c7cd902
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2015,2017 Sven Verdoolaege. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * The views and conclusions contained in the software and documentation
30 * are those of the authors and should not be interpreted as
31 * representing official policies, either expressed or implied, of
32 * Leiden University.
35 #include "clang.h"
36 #include "expr.h"
37 #include "expr_plus.h"
38 #include "id.h"
39 #include "inliner.h"
41 using namespace std;
42 using namespace clang;
44 /* Add an assignment of "expr" to a variable with identifier "id" and
45 * return a pet_expr corresponding to the assigned variable.
47 __isl_give pet_expr *pet_inliner::assign( __isl_take isl_id *id,
48 __isl_take pet_expr *expr)
50 pet_expr *var;
52 var = pet_expr_access_from_id(id, ast_context);
54 assignments.push_back(pair<pet_expr *, pet_expr *>(var, expr));
56 return pet_expr_copy(var);
59 /* Add a scalar argument to the inliner.
60 * "decl" is the declaration of the formal argument.
61 * "name" is the name that should be used in the assignment before
62 * the inlined tree.
63 * "expr" is the actual argument.
65 * Create an identifier called "name" referring to "decl".
66 * Assign it the value of "expr" and keep track of
67 * the substitution of the identifier corresponding to "decl" by
68 * the expression that is assigned the value.
70 void pet_inliner::add_scalar_arg(ValueDecl *decl, const string &name,
71 __isl_take pet_expr *expr)
73 isl_id *id;
74 pet_expr *var;
76 id = pet_id_from_name_and_decl(ctx, name.c_str(), decl);
77 var = assign(id, expr);
78 id = pet_id_from_decl(ctx, decl);
79 add_sub(id, var);
82 /* Add an array argument to the inliner.
83 * "decl" is the declaration of the formal argument.
84 * "expr" is the actual argument and is and access expression.
85 * "is_addr" is set if it is the address of "expr" that is passed
86 * as an argument.
88 * Create identifiers for the arguments of "expr".
89 * Assign each of them the value of the corresponding argument and
90 * replace the argument by the expression that is assigned the value.
91 * Keep track of the substitution of the identifier corresponding
92 * to "decl" by the resulting expression.
94 void pet_inliner::add_array_arg(ValueDecl *decl, __isl_take pet_expr *expr,
95 int is_addr)
97 isl_id *id;
99 for (unsigned j = 0; j < expr->n_arg; ++j) {
100 pet_expr *var;
101 QualType type = ast_context.IntTy;
103 id = pet_id_arg_from_type(ctx, n_arg++, type);
104 var = assign(id, pet_expr_copy(expr->args[j]));
105 expr = pet_expr_set_arg(expr, j, var);
107 if (is_addr)
108 expr = pet_expr_new_unary(0, pet_op_address_of, expr);
109 id = pet_id_from_decl(ctx, decl);
110 add_sub(id, expr);
113 /* Data needed in replace_return_base pet_tree_map_top_down callback.
115 struct replace_return_data {
116 clang::ASTContext &ast_context;
117 isl_id *return_id;
119 replace_return_data(clang::ASTContext &ast_context, isl_id *return_id) :
120 ast_context(ast_context), return_id(return_id) {}
123 extern "C" {
124 static __isl_give pet_tree *replace_return_base(
125 __isl_take pet_tree *tree, void *user);
128 /* This function is called for every subtree of a pet_tree.
129 * If the subtree corresponds to a return statement,
130 * then replace the return statement by an assignment
131 * of the returned expression to data->return_id.
133 static __isl_give pet_tree *replace_return_base(__isl_take pet_tree *tree,
134 void *user)
136 replace_return_data *data = (replace_return_data *) user;
137 int type_size;
138 pet_expr *var;
139 pet_expr *expr;
141 if (pet_tree_get_type(tree) != pet_tree_return)
142 return tree;
144 expr = pet_tree_return_get_expr(tree);
145 pet_tree_free(tree);
147 var = pet_expr_access_from_id(isl_id_copy(data->return_id),
148 data->ast_context);
149 type_size = pet_expr_get_type_size(var);
150 var = pet_expr_access_set_write(var, 1);
151 var = pet_expr_access_set_read(var, 0);
153 expr = pet_expr_new_binary(type_size, pet_op_assign, var, expr);
155 return pet_tree_new_expr(expr);
158 /* Replace any return statement in "tree" by a write to "return_id".
160 static __isl_give pet_tree *replace_return(__isl_take pet_tree *tree,
161 clang::ASTContext &ast_context, __isl_keep isl_id *return_id)
163 replace_return_data data(ast_context, return_id);
164 return pet_tree_map_top_down(tree, &replace_return_base, &data);
167 /* Inline "tree" by applying the substitutions to "tree" and placing
168 * the result in a block after the assignments stored in "assignments".
169 * If "return_id" is not NULL, then any return statement in "tree"
170 * is replaced by a write to "return_id".
172 __isl_give pet_tree *pet_inliner::inline_tree(__isl_take pet_tree *tree,
173 __isl_keep isl_id *return_id)
175 pet_expr *expr;
176 pet_tree *block;
177 int n = assignments.size() + 1;
179 block = pet_tree_new_block(ctx, 1, n);
181 for (unsigned i = 0; i < assignments.size(); ++i) {
182 pet_tree *tree_i;
184 expr = pet_expr_copy(assignments[i].first);
185 expr = pet_expr_access_set_write(expr, 1);
186 expr = pet_expr_access_set_read(expr, 0);
187 tree_i = pet_tree_new_decl_init(expr,
188 pet_expr_copy(assignments[i].second));
189 block = pet_tree_block_add_child(block, tree_i);
192 tree = substitute(tree);
193 if (return_id)
194 tree = replace_return(tree, ast_context, return_id);
195 block = pet_tree_block_add_child(block, tree);
197 return block;
200 /* Free all elements in the assignments.
202 pet_inliner::~pet_inliner()
204 std::vector<std::pair<pet_expr *, pet_expr *> >::iterator it;
206 for (it = assignments.begin(); it != assignments.end(); ++it) {
207 pet_expr_free(it->first);
208 pet_expr_free(it->second);