PIPS
unroll.c
Go to the documentation of this file.
1 /*
2 
3  $Id: unroll.c 23495 2018-10-24 09:19:47Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 
28 #include "genC.h"
29 #include "linear.h"
30 #include "ri.h"
31 #include "effects.h"
32 
33 #include "resources.h"
34 
35 #include "misc.h"
36 #include "ri-util.h"
37 #include "effects-util.h"
38 #include "pipsdbm.h"
39 
40 #include "effects-generic.h"
41 #include "transformations.h"
42 
43 #include "control.h"
44 
45 
46 #include "sac.h"
47 #include "hyperplane.h"
48 
49 #include "properties.h"
50 
51 #include <limits.h>
52 
54 {
55  switch(instruction_tag(i))
56  {
58  return true;
59 
61  {
62  cons * j;
63 
65  j != NIL;
66  j = CDR(j) )
67  {
68  statement s = STATEMENT(CAR(j));
70  return false;
71  }
72  return true;
73  }
74 
80  default:
81  return false;
82  }
83 }
84 
85 typedef struct {
86  int min;
87  int max;
88 } MinMaxVar;
89 
90 static void compute_variable_size(statement s, MinMaxVar* varwidth)
91 {
93 
94  if (width > varwidth->max)
95  varwidth->max = width;
96 
97  if (width < varwidth->min)
98  varwidth->min = width;
99 }
100 
101 static void simd_loop_unroll(statement loop_statement, intptr_t rate)
102 {
103  range r = loop_range(statement_loop(loop_statement));
105  intptr_t irange;
106  if(expression_integer_value(erange,&irange) && irange <=rate) {
107  bool saved[] = {
108  get_bool_property("LOOP_NORMALIZE_ONE_INCREMENT"),
109  get_bool_property("LOOP_NORMALIZE_SKIP_INDEX_SIDE_EFFECT")
110  };
111  set_bool_property("LOOP_NORMALIZE_ONE_INCREMENT",true);
112  set_bool_property("LOOP_NORMALIZE_SKIP_INDEX_SIDE_EFFECT",true);
113  loop_normalize_statement(loop_statement);
114  range r = loop_range(statement_loop(loop_statement));
117  set_bool_property("LOOP_NORMALIZE_ONE_INCREMENT",saved[0]);
118  set_bool_property("LOOP_NORMALIZE_SKIP_INDEX_SIDE_EFFECT",saved[1]);
119  full_loop_unroll(loop_statement);
120  }
121  else
122  {
123  expression lower = range_lower(r);
124  NORMALIZE_EXPRESSION(lower);
125  entity new = entity_undefined;
127  new = make_new_index_entity(loop_index(statement_loop(loop_statement)),"i");
130  }
131  do_loop_unroll(loop_statement,rate,NULL);
132  if (! entity_undefined_p(new)){
133  insert_statement(loop_statement,
135  true);
136  }
137  }
138  free_expression(erange);
139 }
140 
142  /* Compute variable size */
143  MinMaxVar varwidths = { INT_MAX , 0 };
144  int varwidth;
145  gen_context_recurse(loop_body(l), &varwidths,
147 
148  /* Decide between min and max unroll factor */
149  if (get_bool_property("SIMDIZER_AUTO_UNROLL_MINIMIZE_UNROLL"))
150  varwidth = varwidths.max;
151  else
152  varwidth = varwidths.min;
153 
154  /* Round up varwidth to a power of 2 */
155  int regWidth = get_int_property("SAC_SIMD_REGISTER_WIDTH");
156 
157  if ((varwidth > regWidth/2) || (varwidth <= 0))
158  return 1;
159 
160  for(int j = 8; j <= regWidth/2; j*=2)
161  {
162  if (varwidth <= j)
163  {
164  varwidth = j;
165  break;
166  }
167  }
168 
169  /* Unroll as many times as needed by the variables width */
170  return regWidth / varwidth;
171 }
172 
174 {
175  instruction i;
176  loop l;
177  instruction iBody;
178 
179  /* If this is not a loop, keep on recursing */
180  i = statement_instruction(s);
181  if (!instruction_loop_p(i))
182  return true;
183  l = instruction_loop(i);
184 
185  /* Can only simdize certain loops */
186  iBody = statement_instruction(loop_body(l));
187  if (!should_unroll_p(iBody))
188  return true; /* can't do anything */
189 
190  /* Unroll as many times as needed by the variables width */
192 
193  /* Do not recursively analyse the loop */
194  return false;
195 }
196 
198 {
200 
201  /* see if the statement can be SIMDized */
203  {
204  /* and if so, to what extent it may benefit from unrolling */
206  {
207  if (get_subwordSize_from_opcode(o, 0) >= varwidth) //opcode may be used
208  {
209  if (opcode_vectorSize(o) > factor->max)
210  factor->max = opcode_vectorSize(o);
211  if (opcode_vectorSize(o) < factor->min)
212  factor->min = opcode_vectorSize(o);
213  }
214  }
215  }
216 }
217 
219 {
220  MinMaxVar factor;
221  instruction i;
222  loop l;
223  instruction iBody;
224 
225  /* If this is not a loop, keep on recursing */
226  i = statement_instruction(s);
227  if (!instruction_loop_p(i))
228  return true;
229  l = instruction_loop(i);
230 
231  /* Can only simdize certain loops */
232  iBody = statement_instruction(loop_body(l));
233  if (!should_unroll_p(iBody))
234  return true; /* can't do anything */
235 
236  /* look at each of the statements in the body */
237  factor.min = INT_MAX;
238  factor.max = 1;
240  factor.min = factor.min > factor.max ? factor.max : factor.min;
241 
242 
243  /* Decide between min and max unroll factor, and unroll */
244  int unroll_rate = get_bool_property("SIMDIZER_AUTO_UNROLL_MINIMIZE_UNROLL") ? factor.min : factor.max;
245  simd_loop_unroll(s, unroll_rate);
246 
247  /* Do not recursively analyse the loop */
248  return false;
249 }
250 
251 static void simd_unroll_as_needed(statement module_stmt)
252 {
253  /* Choose algorithm to use, and use it */
254  if (get_bool_property("SIMDIZER_AUTO_UNROLL_SIMPLE_CALCULATION"))
255  {
256  gen_recurse(module_stmt, statement_domain,
258  }
259  else
260  {
261  set_simd_treematch((matchTree)db_get_memory_resource(DBR_SIMD_TREEMATCH,"",true));
262  set_simd_operator_mappings(db_get_memory_resource(DBR_SIMD_OPERATOR_MAPPINGS,"",true));
263 
264  gen_recurse(module_stmt, statement_domain,
268  }
269 }
270 bool loop_auto_unroll(const char* mod_name) {
271  // get the resources
272  statement mod_stmt = (statement)
273  db_get_memory_resource(DBR_CODE, mod_name, true);
274 
277 
278  debug_on("SIMDIZER_DEBUG_LEVEL");
279 
280  /* do the job */
281  const char* slabel = get_string_property_or_ask("LOOP_LABEL","enter the label of a loop !");
282  entity elabel = find_label_entity(mod_name,slabel);
283 
284  if(entity_undefined_p(elabel)) {
285  pips_user_error("label %s does not exist !\n", slabel);
286  }
287  else {
288  statement theloopstatement = find_loop_from_label(get_current_module_statement(),elabel);
289  if(!statement_undefined_p(theloopstatement)) {
290  simple_simd_unroll_loop_filter(theloopstatement);
291  }
292  }
293 
294  pips_assert("Statement is consistent after SIMDIZER_AUTO_UNROLL",
295  statement_consistent_p(mod_stmt));
296 
297  // Reorder the module, because new statements have been added
298  module_reorder(mod_stmt);
299  DB_PUT_MEMORY_RESOURCE(DBR_CODE, mod_name, mod_stmt);
300 
301  // update/release resources
304 
305  debug_off();
306 
307  return true;
308 }
309 
310 bool simdizer_auto_unroll(char * mod_name)
311 {
312  // get the resources
313  statement mod_stmt = (statement)
314  db_get_memory_resource(DBR_CODE, mod_name, true);
315 
318 
319  debug_on("SIMDIZER_DEBUG_LEVEL");
320 
321  simd_unroll_as_needed(mod_stmt);
322 
323  pips_assert("Statement is consistent after SIMDIZER_AUTO_UNROLL",
324  statement_consistent_p(mod_stmt));
325 
326  // Reorder the module, because new statements have been added
327  module_reorder(mod_stmt);
328  DB_PUT_MEMORY_RESOURCE(DBR_CODE, mod_name, mod_stmt);
329 
330  // update/release resources
333 
334  debug_off();
335 
336  return true;
337 }
338 
339 static void gather_local_indices(reference r, set s) {
341  if(!ENDP(indices)) {
344  set_union(s,s,xs);
345  set_free(xs);
346  }
347 }
348 
349 static void keep_loop_indices(statement s, list *L) {
350  if(statement_loop_p(s))
351  *L=CONS(STATEMENT,s,*L);
352 }
353 
354 static list do_simdizer_auto_tile_int_to_list(int maxdepth, int path,loop l) {
355  list out = NIL;
356  int rw = simple_simd_unroll_rate(l);
357  while(maxdepth--) {
358  int a = 1;
359  if(path & 1) a=rw;
361  }
362  return out;
363 }
364 
366  if(expression_undefined_p(*tests)) {
368  statement cp = clone_statement(root, cc);
369  /* duplicate effects for the copied statement */
373  statement siter = cp;
374  FOREACH(LOOP,li,l)
375  siter = loop_body(statement_loop(siter));
376  free_clone_context(cc);
377  return cp;
378  }
379  else {
380  int npath = path << 1 ;
381  return do_simdizer_auto_tile_generate_all_tests(root, maxdepth, npath+1, tests+1);
382  /*
383  int npath = path << 1 ;
384  statement trueb = do_simdizer_auto_tile_generate_all_tests(root, maxdepth, npath+1, tests+1);
385  statement falseb = do_simdizer_auto_tile_generate_all_tests(root, maxdepth, npath, tests+1);
386  return
387  instruction_to_statement(
388  make_instruction_test(
389  make_test(
390  *tests,
391  trueb,
392  falseb
393  )
394  )
395  );
396  */
397  }
398 }
399 
400 static statement simdizer_auto_tile_generate_all_tests(statement root, int maxdepth, expression tests[1+maxdepth]) {
401  return do_simdizer_auto_tile_generate_all_tests(root,maxdepth,0,&tests[0]);
402 }
403 
404 static void stmt_rm_labels(statement s)
405 {
406  (void) statement_remove_useless_label(s, false);
407 }
408 
409 bool simdizer_auto_tile(const char * module_name) {
410  bool success = false;
414 
415  /* do the job */
416  const char* slabel = get_string_property_or_ask("LOOP_LABEL","enter the label of a loop !");
417  entity elabel = find_label_entity(module_name,slabel);
418 
419  if(entity_undefined_p(elabel)) {
420  pips_user_error("label %s does not exist !\n", slabel);
421  }
422  else {
423  statement theloopstatement = find_loop_from_label(get_current_module_statement(),elabel);
424  if(!statement_undefined_p(theloopstatement)) {
425  if(perfectly_nested_loop_p(theloopstatement)) {
426  /* retrieve loop indices that are referenced as last element */
429  list tloops = NIL;
431  list allloops =gen_copy_seq(tloops);
432  FOREACH(STATEMENT,l,allloops) {
434  gen_remove_once(&tloops,l);
435  }
436  theloopstatement=STATEMENT(CAR((tloops)));
437  //allloops=gen_nreverse(allloops);
438  while(theloopstatement!=STATEMENT(CAR(allloops))) POP(allloops);
439  set_free(indices);
441 
442  /* build tests */
443  int max_unroll_rate = simple_simd_unroll_rate(statement_loop(theloopstatement));
444  int nloops=gen_length(allloops);
445  /* iterate over all possible combination of tests */
446  expression alltests[1+nloops];
447  alltests[nloops] = expression_undefined ;
448  int j=0;
449  FOREACH(STATEMENT,sl,allloops) {
450  alltests[j++]=MakeBinaryCall(
453  int_to_expression(2*max_unroll_rate)
454  );
455  }
456  /* create the if's recursively */
457  statement root =
459  theloopstatement,
460  nloops,
461  alltests);
463  *theloopstatement=*root;
464  loop_label(statement_loop(theloopstatement))=elabel;
465  success=true;
466 
467  /* validate */
470  }
471  else pips_user_error("loop is not perfectly nested !\n");
472  }
473  else pips_user_error("label is not on a loop!\n");
474  }
475 
479  return success;
480 }
481 
482 
483 
484 
int get_int_property(const string)
clone_context make_clone_context(entity a1, entity a2, list a3, statement a4)
Definition: cloning.c:52
void free_clone_context(clone_context p)
Definition: cloning.c:19
effects copy_effects(effects p)
EFFECTS.
Definition: effects.c:532
bool statement_consistent_p(statement p)
Definition: ri.c:2195
void free_expression(expression p)
Definition: ri.c:853
static FILE * out
Definition: alias_check.c:128
statement clone_statement(statement s, clone_context cc)
clone_statement.c
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
static list loops
#define min(a, b)
void set_cumulated_rw_effects(statement_effects)
effects load_cumulated_rw_effects(statement)
void store_cumulated_rw_effects(statement, effects)
void reset_cumulated_rw_effects(void)
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
bool success
Definition: gpips-local.h:59
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
statement get_current_module_statement(void)
Get the current module statement.
Definition: static.c:208
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
bool perfectly_nested_loop_p(statement stat)
Test if a statement is a perfect loop-nest.
Definition: loop.c:543
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
void gen_remove_once(list *pl, const void *o)
Remove the first occurence of o in list pl:
Definition: list.c:691
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
list gen_last(list l)
Return the last element of a list.
Definition: list.c:578
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
loop statement_loop(statement)
Get the loop of a statement.
Definition: statement.c:1374
bool statement_loop_p(statement)
Definition: statement.c:349
statement make_assign_statement(expression, expression)
Definition: statement.c:583
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
void statement_remove_useless_label(statement, bool *)
remove the label of a statement if the statement is not unstructured.
Definition: statement.c:4275
void do_symbolic_tiling(statement, list)
symbolic_tiling.c
static list indices
Definition: icm.c:204
void full_loop_unroll(statement loop_statement)
get rid of the loop by body replication;
Definition: loop_unroll.c:788
void do_loop_unroll(statement loop_statement, int rate, void(*statement_post_processor)(statement))
loop_unroll.c
Definition: loop_unroll.c:714
#define debug_on(env)
Definition: misc-local.h:157
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define debug_off()
Definition: misc-local.h:160
#define pips_user_error
Definition: misc-local.h:147
set set_assign_list(set, const list)
assigns a list contents to a set all duplicated elements are lost
Definition: set.c:474
void set_free(set)
Definition: set.c:332
bool set_belong_p(const set, const void *)
Definition: set.c:194
set set_union(set, const set, const set)
Definition: set.c:211
@ set_pointer
Definition: newgen_set.h:44
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
void reset_simd_operator_mappings()
Definition: operatorid.c:48
void set_simd_operator_mappings(void *m)
operatorid.c
Definition: operatorid.c:43
void set_bool_property(const char *, bool)
const char * get_string_property_or_ask(const char *, const char[])
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define GREATER_THAN_OPERATOR_NAME
#define NORMALIZE_EXPRESSION(e)
@ range_to_nbiter
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
set get_referenced_entities(void *elem)
retrieves the set of entities used in elem beware that this entities may be formal parameters,...
Definition: entity.c:3063
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
expression range_to_expression(range r, enum range_to_expression_mode mode)
computes the distance between the lower bound and the upper bound of the range
Definition: eval.c:963
bool expression_integer_value(expression e, intptr_t *pval)
Definition: eval.c:792
bool simplify_expression(expression *pexp)
use polynomials to simplify an expression in some cases this operation can change the basic of the ex...
Definition: expression.c:3770
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
expression MakeBinaryCall(entity f, expression eg, expression ed)
Creates a call expression to a function with 2 arguments.
Definition: expression.c:354
expression int_to_expression(_int i)
transform an int into an expression and generate the corresponding entity if necessary; it is not cle...
Definition: expression.c:1188
void AddEntityToCurrentModule(entity)
Add a variable entity to the current module declarations.
Definition: variable.c:260
entity find_label_entity(const char *, const char *)
util.c
Definition: util.c:43
entity make_new_index_entity(entity, string)
Definition: variable.c:1851
#define loop_body(x)
Definition: ri.h:1644
#define LOOP(x)
LOOP.
Definition: ri.h:1606
#define normalized_complex_p(x)
Definition: ri.h:1782
#define instruction_loop_p(x)
Definition: ri.h:1518
#define range_upper(x)
Definition: ri.h:2290
#define instruction_loop(x)
Definition: ri.h:1520
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define entity_undefined_p(x)
Definition: ri.h:2762
#define reference_domain
newgen_range_domain_defined
Definition: ri.h:338
#define entity_undefined
Definition: ri.h:2761
#define expression_undefined
Definition: ri.h:1223
@ is_instruction_goto
Definition: ri.h:1473
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_sequence
Definition: ri.h:1469
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define expression_normalized(x)
Definition: ri.h:1249
#define sequence_statements(x)
Definition: ri.h:2360
#define reference_indices(x)
Definition: ri.h:2328
#define instruction_sequence(x)
Definition: ri.h:1514
#define loop_label(x)
Definition: ri.h:1646
#define expression_undefined_p(x)
Definition: ri.h:1224
#define range_lower(x)
Definition: ri.h:2288
#define statement_instruction(x)
Definition: ri.h:2458
#define loop_range(x)
Definition: ri.h:1642
#define statement_undefined_p(x)
Definition: ri.h:2420
#define loop_index(x)
Definition: ri.h:1640
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
int get_subwordSize_from_opcode(opcode oc, int argNum)
Definition: codegen.c:246
void reset_simd_treematch(void)
Definition: treematch.c:52
void set_simd_treematch(matchTree)
treematch.c
Definition: treematch.c:46
int effective_variables_width(instruction)
varwidth.c
Definition: varwidth.c:85
list match_statement(statement)
return a list of matching statements
Definition: treematch.c:237
#define opcode_vectorSize(x)
Definition: sac_private.h:291
#define MATCH(x)
MATCH.
Definition: sac_private.h:221
#define match_type(x)
Definition: sac_private.h:251
#define opcodeClass_opcodes(x)
Definition: sac_private.h:538
#define OPCODE(x)
OPCODE.
Definition: sac_private.h:257
Pvecteur cp
pointeur sur l'egalite ou l'inegalite courante
Definition: sc_read.c:87
static char * x
Definition: split_file.c:159
#define intptr_t
Definition: stdint.in.h:294
Definition: pip__tab.h:30
int max
Definition: unroll.c:87
int min
Definition: unroll.c:86
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
void loop_normalize_statement(statement)
loop_normalize.c
statement find_loop_from_label(statement, entity)
Definition: util.c:218
static void gather_local_indices(reference r, set s)
Definition: unroll.c:339
bool simdizer_auto_unroll(char *mod_name)
Definition: unroll.c:310
static void compute_parallelism_factor(statement s, MinMaxVar *factor)
Definition: unroll.c:197
static bool full_simd_unroll_loop_filter(statement s)
Definition: unroll.c:218
static void simd_loop_unroll(statement loop_statement, intptr_t rate)
Definition: unroll.c:101
static list do_simdizer_auto_tile_int_to_list(int maxdepth, int path, loop l)
Definition: unroll.c:354
bool loop_auto_unroll(const char *mod_name)
unroll.c
Definition: unroll.c:270
bool simdizer_auto_tile(const char *module_name)
Definition: unroll.c:409
static statement simdizer_auto_tile_generate_all_tests(statement root, int maxdepth, expression tests[1+maxdepth])
Definition: unroll.c:400
static bool simple_simd_unroll_loop_filter(statement s)
Definition: unroll.c:173
static int simple_simd_unroll_rate(loop l)
Definition: unroll.c:141
static bool should_unroll_p(instruction i)
Definition: unroll.c:53
static void stmt_rm_labels(statement s)
Definition: unroll.c:404
static statement do_simdizer_auto_tile_generate_all_tests(statement root, int maxdepth, int path, expression *tests)
Definition: unroll.c:365
static void keep_loop_indices(statement s, list *L)
Definition: unroll.c:349
static void compute_variable_size(statement s, MinMaxVar *varwidth)
Definition: unroll.c:90
static void simd_unroll_as_needed(statement module_stmt)
Definition: unroll.c:251