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
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
37 #include "expr_plus.h"
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
)
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
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
)
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
);
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
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
,
99 for (unsigned j
= 0; j
< expr
->n_arg
; ++j
) {
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
);
108 expr
= pet_expr_new_unary(0, pet_op_address_of
, expr
);
109 id
= pet_id_from_decl(ctx
, decl
);
113 /* Data needed in replace_return_base pet_tree_map_top_down callback.
115 struct replace_return_data
{
116 clang::ASTContext
&ast_context
;
119 replace_return_data(clang::ASTContext
&ast_context
, isl_id
*return_id
) :
120 ast_context(ast_context
), return_id(return_id
) {}
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
,
136 replace_return_data
*data
= (replace_return_data
*) user
;
141 if (pet_tree_get_type(tree
) != pet_tree_return
)
144 expr
= pet_tree_return_get_expr(tree
);
147 var
= pet_expr_access_from_id(isl_id_copy(data
->return_id
),
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
)
177 int n
= assignments
.size() + 1;
179 block
= pet_tree_new_block(ctx
, 1, n
);
181 for (unsigned i
= 0; i
< assignments
.size(); ++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
);
194 tree
= replace_return(tree
, ast_context
, return_id
);
195 block
= pet_tree_block_add_child(block
, tree
);
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
);