PandA-2024.02
IR_lowering.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
47 #include "IR_lowering.hpp"
48 
49 #include "config_HAVE_ASSERTS.hpp" // for HAVE_ASSERTS
50 
51 #include "Parameter.hpp" // for Parameter
52 #include "application_manager.hpp" // for application_manager, app...
53 #include "custom_map.hpp" // for unordered_map, operator!=
54 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_VERY_PEDANTIC
55 #include "design_flow_graph.hpp" // for DesignFlowGraph, DesignF...
56 #include "design_flow_manager.hpp" // for DesignFlowManager, Desig...
57 #include "design_flow_step_factory.hpp" // for DesignFlowManagerConstRef
58 #include "exceptions.hpp" // for THROW_ASSERT, THROW_UNRE...
59 #include "graph.hpp" // for vertex
60 #include "hash_helper.hpp" // for hash
61 #include "hls_device.hpp" // for HLS_device, HLS_deviceRef
62 #include "hls_manager.hpp" // for HLS_manager
63 #include "math_function.hpp" // for floor_log2, exact_log2
64 #include "string_manipulation.hpp" // for STR, GET_CLASS
65 #include "technology_flow_step.hpp" // for TechnologyFlowStep_Type
66 #include "technology_flow_step_factory.hpp" // for TechnologyFlowStepFactory
67 #include "technology_manager.hpp" // for LIBRARY_STD_FU, technolo...
68 #include "technology_node.hpp" // for functional_unit, operation
69 #include "time_info.hpp" // for time_info
70 #include "tree_basic_block.hpp" // for bloc
71 #include "tree_common.hpp" // for plus_expr_K, lshift_expr_K
72 #include "tree_helper.hpp" // for tree_helper
73 #include "tree_manager.hpp" // for tree_manager
74 #include "tree_manipulation.hpp" // for tree_manipulation, Param...
75 #include "tree_node.hpp" // for tree_nodeRef, gimple_assign
76 #include "tree_reindex.hpp"
77 #include <cmath> // for ceil
78 #include <cstddef> // for size_t
79 #include <limits>
80 #include <vector> // for vector
81 
82 IR_lowering::IR_lowering(const ParameterConstRef Param, const application_managerRef _AppM, unsigned int _function_id,
83  const DesignFlowManagerConstRef _design_flow_manager)
84  : FunctionFrontendFlowStep(_AppM, _function_id, IR_LOWERING, _design_flow_manager, Param)
85 {
86  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
87 }
88 
91 {
93  switch(relationship_type)
94  {
96  {
97  relationships.insert(std::make_pair(BLOCK_FIX, SAME_FUNCTION));
98  relationships.insert(std::make_pair(FIX_STRUCTS_PASSED_BY_VALUE, SAME_FUNCTION));
99  relationships.insert(std::make_pair(FIX_VDEF, SAME_FUNCTION));
100  relationships.insert(std::make_pair(FUNCTION_ANALYSIS, WHOLE_APPLICATION));
101  relationships.insert(std::make_pair(HWCALL_INJECTION, SAME_FUNCTION));
102  relationships.insert(std::make_pair(REBUILD_INITIALIZATION, SAME_FUNCTION));
103  relationships.insert(std::make_pair(REMOVE_CLOBBER_GA, SAME_FUNCTION));
104  relationships.insert(std::make_pair(SWITCH_FIX, SAME_FUNCTION));
105  break;
106  }
108  {
109  break;
110  }
112  {
113  break;
114  }
115  default:
116  THROW_UNREACHABLE("");
117  }
118  return relationships;
119 }
120 
121 IR_lowering::~IR_lowering() = default;
122 
124 {
125  TM = AppM->get_tree_manager();
127 }
128 
130  const DesignFlowStep::RelationshipType relationship_type)
131 {
132  switch(relationship_type)
133  {
135  {
136  break;
137  }
139  {
140  const DesignFlowGraphConstRef design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
141  const auto* technology_flow_step_factory = GetPointer<const TechnologyFlowStepFactory>(
142  design_flow_manager.lock()->CGetDesignFlowStepFactory("Technology"));
143  const std::string technology_flow_signature =
145  const vertex technology_flow_step = design_flow_manager.lock()->GetDesignFlowStep(technology_flow_signature);
146  const DesignFlowStepRef technology_design_flow_step =
147  technology_flow_step ?
148  design_flow_graph->CGetDesignFlowStepInfo(technology_flow_step)->design_flow_step :
149  technology_flow_step_factory->CreateTechnologyFlowStep(TechnologyFlowStep_Type::LOAD_TECHNOLOGY);
150  relationship.insert(technology_design_flow_step);
151  break;
152  }
154  {
155  break;
156  }
157  default:
158  THROW_UNREACHABLE("");
159  }
160  FunctionFrontendFlowStep::ComputeRelationships(relationship, relationship_type);
161 }
162 
164 
166 {
178 };
179 
190 struct mult_cost
191 {
192  short cost;
193  short latency;
194 };
195 
214 struct algorithm
215 {
216  struct mult_cost cost;
217  short ops;
218  /* The size of the OP and LOG fields are not directly related to the
219  word size, but the worst-case algorithms will be if we have few
220  consecutive ones or zeros, i.e., a multiplicand like 10101010101...
221  In that case we will generate shift-by-2, add, shift-by-2, add,...,
222  in total wordsize operations. */
223  enum alg_code op[64];
224  char log[64];
225 };
226 
230 #define MULT_COST_LESS(X, Y) ((X).cost < (Y) || ((X).cost == (Y) && (X).latency < (Y)))
231 
236 #define CHEAPER_MULT_COST(X, Y) ((X).cost < (Y).cost || ((X).cost == (Y).cost && (X).latency < (Y).latency))
237 
238 static CustomUnorderedMap<std::pair<unsigned int, unsigned long long>, std::pair<enum alg_code, struct mult_cost>>
240 
246 static void synth_mult(struct algorithm& alg_out, unsigned long long t, const struct mult_cost& cost_limit,
247  unsigned long long data_bitsize, tree_managerRef& TM)
248 {
249  int m;
250  struct algorithm alg_in, best_alg;
251  struct mult_cost best_cost;
252  struct mult_cost new_limit;
253  short op_cost, op_latency;
254  unsigned long long int orig_t = t;
255  unsigned long long int q;
256  auto maxm = static_cast<int>(std::min(32ull, data_bitsize));
257  bool cache_hit = false;
258  enum alg_code cache_alg = alg_zero;
261  best_alg.ops = 0;
262 
265  alg_out.cost.cost = static_cast<short>(cost_limit.cost + 1);
266  alg_out.cost.latency = static_cast<short>(cost_limit.latency + 1);
267 
268  if(cost_limit.cost < 0 || (cost_limit.cost == 0 && cost_limit.latency <= 0))
269  {
270  return;
271  }
272 
274  if(t == 1)
275  {
276  alg_out.ops = 1;
277  alg_out.cost.cost = 0;
278  alg_out.cost.latency = 0;
279  alg_out.op[0] = alg_m;
280  return;
281  }
282 
285  if(t == 0)
286  {
287  alg_out.ops = 1;
288  alg_out.cost.cost = 0 /*zero_cost[speed]*/;
289  alg_out.cost.latency = 0 /*zero_cost[speed]*/;
290  alg_out.op[0] = alg_zero;
291  return;
292  }
293  best_cost = cost_limit;
294  if(alg_hash.find(std::make_pair(data_bitsize, t)) != alg_hash.end())
295  {
296  std::pair<enum alg_code, struct mult_cost> res = alg_hash.find(std::make_pair(data_bitsize, t))->second;
297  cache_alg = res.first;
298  if(cache_alg == alg_impossible)
299  {
302  if(!CHEAPER_MULT_COST(res.second, cost_limit))
303  {
308  return;
309  }
310 
315  }
316  else
317  {
318  if(CHEAPER_MULT_COST(cost_limit, res.second))
319  {
324  return;
325  }
326  cache_hit = true;
327 
328  switch(cache_alg)
329  {
330  case alg_shift:
331  goto do_alg_shift;
332 
333  case alg_add_t_m2:
334  case alg_sub_t_m2:
335  goto do_alg_addsub_t_m2;
336 
337  case alg_add_factor:
338  case alg_sub_factor:
339  goto do_alg_addsub_factor;
340 
341  case alg_add_t2_m:
342  goto do_alg_add_t2_m;
343 
344  case alg_sub_t2_m:
345  goto do_alg_sub_t2_m;
346  case alg_impossible:
347  case alg_m:
348  case alg_unknown:
349  case alg_zero:
350  default:
351  THROW_ERROR("condition not expected");
352  }
353  }
354  }
355 
359  if((t & 1) == 0)
360  {
361  do_alg_shift:
362  m = static_cast<int>(floor_log2(t & -t)); /* m = number of low zero bits */
363  if(m < maxm)
364  {
365  q = t >> m;
366  /* The function expand_shift will choose between a shift and
367  a sequence of additions, so the observed cost is given as
368  MIN (m * add_cost[speed][mode], shift_cost[speed][mode][m]). */
369  op_cost = static_cast<short>(m * 1 /*add_cost[speed][mode]*/);
370  if(0 /*shift_cost[speed][mode][m]*/ < op_cost)
371  {
372  op_cost = 0 /*shift_cost[speed][mode][m]*/;
373  }
374  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
375  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
376  synth_mult(alg_in, q, new_limit, data_bitsize, TM);
377 
378  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
379  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
380  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
381  {
382  best_cost = alg_in.cost;
383  std::swap(alg_in, best_alg);
384  best_alg.log[best_alg.ops] = static_cast<char>(m);
385  best_alg.op[best_alg.ops] = alg_shift;
386  }
387 
391  if(static_cast<long long int>(orig_t) < 0)
392  {
396  q = ~(~orig_t >> m);
400  op_cost = static_cast<short>(m * 1) /*add_cost[speed][mode]*/;
401  if(0 /*shift_cost[speed][mode][m]*/ < op_cost)
402  {
403  op_cost = 0 /*shift_cost[speed][mode][m]*/;
404  }
405  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
406  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
407  synth_mult(alg_in, q, new_limit, data_bitsize, TM);
408 
409  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
410  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
411  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
412  {
413  best_cost = alg_in.cost;
414  std::swap(alg_in, best_alg);
415  best_alg.log[best_alg.ops] = static_cast<char>(m);
416  best_alg.op[best_alg.ops] = alg_shift;
417  }
418  }
419  }
420  if(cache_hit)
421  {
422  goto done;
423  }
424  }
425 
427  if((t & 1) != 0)
428  {
429  unsigned long long int w;
430 
431  do_alg_addsub_t_m2:
432  for(w = 1; (w & t) != 0; w <<= 1)
433  {
434  ;
435  }
441  if(w == 0 || (w > 2
444  && t != 3))
445  {
448  op_cost = 1 /*add_cost[speed][mode]*/;
449  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
450  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
451  synth_mult(alg_in, t + 1, new_limit, data_bitsize, TM);
452 
453  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
454  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
455  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
456  {
457  best_cost = alg_in.cost;
458  std::swap(alg_in, best_alg);
459  best_alg.log[best_alg.ops] = 0;
460  best_alg.op[best_alg.ops] = alg_sub_t_m2;
461  }
462  }
463  else
464  {
467  op_cost = 1 /*add_cost[speed][mode]*/;
468  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
469  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
470  synth_mult(alg_in, t - 1, new_limit, data_bitsize, TM);
471 
472  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
473  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
474  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
475  {
476  best_cost = alg_in.cost;
477  std::swap(alg_in, best_alg);
478  best_alg.log[best_alg.ops] = 0;
479  best_alg.op[best_alg.ops] = alg_add_t_m2;
480  }
481  }
482 
485  m = static_cast<int>(exact_log2(-orig_t + 1));
486  if(m >= 0 && m < maxm)
487  {
488  op_cost = 1 /*shiftsub1_cost[speed][mode][m]*/;
489  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
490  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
491  synth_mult(alg_in, static_cast<unsigned long long int>(-orig_t + 1) >> m, new_limit, data_bitsize, TM);
492 
493  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
494  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
495  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
496  {
497  best_cost = alg_in.cost;
498  std::swap(alg_in, best_alg);
499  best_alg.log[best_alg.ops] = static_cast<char>(m);
500  best_alg.op[best_alg.ops] = alg_sub_t_m2;
501  }
502  }
503 
504  if(cache_hit)
505  {
506  goto done;
507  }
508  }
509 
520 do_alg_addsub_factor:
521  for(m = static_cast<int>(floor_log2(t - 1)); m >= 2; m--)
522  {
523  unsigned long long int d;
524 
525  d = (1ULL << m) + 1;
526  if(t % d == 0 && t > d && m < maxm && (!cache_hit || cache_alg == alg_add_factor))
527  {
534  op_cost = 1 /*add_cost[speed][mode]*/ + 0 /*shift_cost[speed][mode][m]*/;
535  // if (1/*shiftadd_cost[speed][mode][m]*/ < op_cost)
536  //{
537  // op_cost = 1/*shiftadd_cost[speed][mode][m]*/;
538  // op_latency = op_cost;
539  //}
540  // else
541  op_latency = 1 /*add_cost[speed][mode]*/;
542 
543  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
544  new_limit.latency = static_cast<short>(best_cost.latency - op_latency);
545  synth_mult(alg_in, t / d, new_limit, data_bitsize, TM);
546 
547  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
548  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_latency);
549  if(alg_in.cost.latency < op_cost)
550  {
551  alg_in.cost.latency = op_cost;
552  }
553  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
554  {
555  best_cost = alg_in.cost;
556  std::swap(alg_in, best_alg);
557  best_alg.log[best_alg.ops] = static_cast<char>(m);
558  best_alg.op[best_alg.ops] = alg_add_factor;
559  }
561  break;
562  }
563 
564  d = (1ULL << m) - 1;
565  if(t % d == 0 && t > d && m < maxm && (!cache_hit || cache_alg == alg_sub_factor))
566  {
573  op_cost = 1 /*add_cost[speed][mode]*/ + 0 /*shift_cost[speed][mode][m]*/;
574  // if (1/*shiftsub0_cost[speed][mode][m]*/ < op_cost)
575  //{
576  // op_cost = 1/*shiftsub0_cost[speed][mode][m]*/;
577  // op_latency = op_cost;
578  //}
579  // else
580  op_latency = 1 /*add_cost[speed][mode]*/;
581 
582  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
583  new_limit.latency = static_cast<short>(best_cost.latency - op_latency);
584  synth_mult(alg_in, t / d, new_limit, data_bitsize, TM);
585 
586  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
587  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_latency);
588  if(alg_in.cost.latency < op_cost)
589  {
590  alg_in.cost.latency = op_cost;
591  }
592  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
593  {
594  best_cost = alg_in.cost;
595  std::swap(alg_in, best_alg);
596  best_alg.log[best_alg.ops] = static_cast<char>(m);
597  best_alg.op[best_alg.ops] = alg_sub_factor;
598  }
599  break;
600  }
601  }
602  if(cache_hit)
603  {
604  goto done;
605  }
606 
609  if((t & 1) != 0)
610  {
611  do_alg_add_t2_m:
612  q = t - 1;
613  q = q & -q;
614  m = static_cast<int>(exact_log2(q));
615  if(m >= 0 && m < maxm)
616  {
617  op_cost = 1 /*shiftadd_cost[speed][mode][m]*/;
618  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
619  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
620  synth_mult(alg_in, (t - 1) >> m, new_limit, data_bitsize, TM);
621 
622  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
623  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
624  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
625  {
626  best_cost = alg_in.cost;
627  std::swap(alg_in, best_alg);
628  best_alg.log[best_alg.ops] = static_cast<char>(m);
629  best_alg.op[best_alg.ops] = alg_add_t2_m;
630  }
631  }
632  if(cache_hit)
633  {
634  goto done;
635  }
636 
637  do_alg_sub_t2_m:
638  q = t + 1;
639  q = q & -q;
640  m = static_cast<int>(exact_log2(q));
641  if(m >= 0 && m < maxm)
642  {
643  op_cost = 1 /*shiftsub0_cost[speed][mode][m]*/;
644  new_limit.cost = static_cast<short>(best_cost.cost - op_cost);
645  new_limit.latency = static_cast<short>(best_cost.latency - op_cost);
646  synth_mult(alg_in, (t + 1) >> m, new_limit, data_bitsize, TM);
647 
648  alg_in.cost.cost = static_cast<short>(alg_in.cost.cost + op_cost);
649  alg_in.cost.latency = static_cast<short>(alg_in.cost.latency + op_cost);
650  if(CHEAPER_MULT_COST(alg_in.cost, best_cost))
651  {
652  best_cost = alg_in.cost;
653  std::swap(alg_in, best_alg);
654  best_alg.log[best_alg.ops] = static_cast<char>(m);
655  best_alg.op[best_alg.ops] = alg_sub_t2_m;
656  }
657  }
658  if(cache_hit)
659  {
660  goto done;
661  }
662  }
663 
664 done:
666  if(!CHEAPER_MULT_COST(best_cost, cost_limit))
667  {
673  alg_hash[std::make_pair(data_bitsize, t)] = std::make_pair(alg_impossible, cost_limit);
674  return;
675  }
676 
678  if(!cache_hit)
679  {
680  mult_cost last_limit = {best_cost.cost, best_cost.latency};
681  alg_hash[std::make_pair(data_bitsize, t)] = std::make_pair(best_alg.op[best_alg.ops], last_limit);
682  }
683 
686  if(best_alg.ops == 64)
687  {
688  return;
689  }
690 
694  alg_out = best_alg;
695  alg_out.ops = static_cast<short>(best_alg.ops + 1);
696 }
697 
706 static bool choose_mult_variant(unsigned long long data_bitsize, long long int val, struct algorithm& alg,
707  enum mult_variant& variant, short int Mult_cost, tree_managerRef& TM)
708 {
709  struct algorithm alg2;
710  struct mult_cost limit;
711  short int op_cost;
712 
714  if(Mult_cost < 0)
715  {
716  return false;
717  }
718 
722  op_cost = static_cast<short>(2 * data_bitsize * 1 /*add_cost[speed][mode]*/);
723  if(Mult_cost > op_cost)
724  {
725  Mult_cost = op_cost;
726  }
727 
728  variant = basic_variant;
729  limit.cost = Mult_cost;
730  limit.latency = Mult_cost;
731  synth_mult(alg, static_cast<unsigned long long int>(val), limit, data_bitsize, TM);
732 
733  /* This works only if the inverted value actually fits in an
734  `unsigned int' */
735  if(8 * sizeof(int) >= data_bitsize)
736  {
737  op_cost = 1 /*neg_cost[speed][mode]*/;
738  if(MULT_COST_LESS(alg.cost, Mult_cost))
739  {
740  limit.cost = static_cast<short>(alg.cost.cost - op_cost);
741  limit.latency = static_cast<short>(alg.cost.latency - op_cost);
742  }
743  else
744  {
745  limit.cost = static_cast<short>(Mult_cost - op_cost);
746  limit.latency = static_cast<short>(Mult_cost - op_cost);
747  }
748 
749  synth_mult(alg2, static_cast<unsigned long long int>(-val), limit, data_bitsize, TM);
750  alg2.cost.cost = static_cast<short>(alg2.cost.cost + op_cost);
751  alg2.cost.latency = static_cast<short>(alg2.cost.latency + op_cost);
752  if(CHEAPER_MULT_COST(alg2.cost, alg.cost))
753  {
754  alg = alg2, variant = negate_variant;
755  }
756  }
757 
758  /* This proves very useful for division-by-constant. */
759  op_cost = 1 /*add_cost[speed][mode]*/;
760  if(MULT_COST_LESS(alg.cost, Mult_cost))
761  {
762  limit.cost = static_cast<short>(alg.cost.cost - op_cost);
763  limit.latency = static_cast<short>(alg.cost.latency - op_cost);
764  }
765  else
766  {
767  limit.cost = static_cast<short>(Mult_cost - op_cost);
768  limit.latency = static_cast<short>(Mult_cost - op_cost);
769  }
770 
771  synth_mult(alg2, static_cast<unsigned long long int>(val - 1), limit, data_bitsize, TM);
772  alg2.cost.cost = static_cast<short>(alg2.cost.cost + op_cost);
773  alg2.cost.latency = static_cast<short>(alg2.cost.latency + op_cost);
774  if(CHEAPER_MULT_COST(alg2.cost, alg.cost))
775  {
776  alg = alg2, variant = add_variant;
777  }
778 
779  return MULT_COST_LESS(alg.cost, Mult_cost);
780 }
781 
783  const struct algorithm& alg, enum mult_variant& variant,
784  const tree_nodeRef& stmt, const blocRef& block, const tree_nodeRef& type,
785  const std::string& srcp_default)
786 {
787  long long int val_so_far = 0;
788  tree_nodeRef accum, tem;
789  int opno;
790 #if HAVE_ASSERTS
791  auto data_bitsize = tree_helper::Size(tree_helper::CGetType(type));
792  auto data_mask = data_bitsize >= 64 ? ~0ULL : (1ULL << data_bitsize) - 1;
793 #endif
794  tree_nodeRef tem_ga;
795  tree_nodeRef COST0 = TM->CreateUniqueIntegerCst(0, type);
796  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Expanding " + op0->ToString());
797 
798  /* ACCUM starts out either as OP0 or as a zero, depending on
799  the first operation. */
800 
801  if(alg.op[0] == alg_zero)
802  {
803  accum = COST0;
804  val_so_far = 0;
805  }
806  else if(alg.op[0] == alg_m)
807  {
808  accum = op0;
809  val_so_far = 1;
810  }
811  else
812  {
813  THROW_ERROR("condition not expected");
814  }
815 
816  for(opno = 1; opno < alg.ops; opno++)
817  {
818  auto log = alg.log[opno];
819  tree_nodeRef log_node;
820 
821  if(log == 0)
822  {
823  log_node = COST0;
824  }
825  else
826  {
827  log_node = TM->CreateUniqueIntegerCst(static_cast<long long int>(log), type);
828  }
829 
830  switch(alg.op[opno])
831  {
832  case alg_shift:
833  tem = tree_man->create_binary_operation(type, accum, log_node, srcp_default, lshift_expr_K);
834  tem_ga = tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
835  block->PushBefore(tem_ga, stmt, AppM);
836  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
837  val_so_far <<= log;
838  break;
839 
840  case alg_add_t_m2:
841  if(log_node != COST0)
842  {
843  tem = tree_man->create_binary_operation(type, op0, log_node, srcp_default, lshift_expr_K);
844  tem_ga =
845  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
846  block->PushBefore(tem_ga, stmt, AppM);
847  tem = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
848  }
849  else
850  {
851  tem = op0;
852  }
853  if(accum != COST0)
854  {
855  accum = tree_man->create_binary_operation(type, accum, tem, srcp_default, plus_expr_K);
856  tem_ga =
857  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
858  block->PushBefore(tem_ga, stmt, AppM);
859  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
860  }
861  else
862  {
863  accum = tem;
864  }
865  val_so_far += 1LL << log;
866  break;
867 
868  case alg_sub_t_m2:
869  if(log_node != COST0)
870  {
871  tem = tree_man->create_binary_operation(type, op0, log_node, srcp_default, lshift_expr_K);
872  tem_ga =
873  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
874  block->PushBefore(tem_ga, stmt, AppM);
875  tem = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
876  }
877  else
878  {
879  tem = op0;
880  }
881  if(accum != COST0)
882  {
883  accum = tree_man->create_binary_operation(type, accum, tem, srcp_default, minus_expr_K);
884  }
885  else
886  {
887  accum = tree_man->create_unary_operation(type, tem, srcp_default, negate_expr_K);
888  }
889  tem_ga =
890  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
891  block->PushBefore(tem_ga, stmt, AppM);
892  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
893  val_so_far -= 1LL << log;
894  break;
895 
896  case alg_add_t2_m:
897  if(log_node != COST0 && accum != COST0)
898  {
899  accum = tree_man->create_binary_operation(type, accum, log_node, srcp_default, lshift_expr_K);
900  tem_ga =
901  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
902  block->PushBefore(tem_ga, stmt, AppM);
903  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
904  }
905  if(accum != COST0)
906  {
907  accum = tree_man->create_binary_operation(type, accum, op0, srcp_default, plus_expr_K);
908  tem_ga =
909  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
910  block->PushBefore(tem_ga, stmt, AppM);
911  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
912  }
913  else
914  {
915  accum = op0;
916  }
917  val_so_far = (val_so_far << log) + 1;
918  break;
919 
920  case alg_sub_t2_m:
921  if(log_node != COST0 && accum != COST0)
922  {
923  accum = tree_man->create_binary_operation(type, accum, log_node, srcp_default, lshift_expr_K);
924  tem_ga =
925  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
926  block->PushBefore(tem_ga, stmt, AppM);
927  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
928  }
929  if(accum != COST0)
930  {
931  accum = tree_man->create_binary_operation(type, accum, op0, srcp_default, minus_expr_K);
932  }
933  else
934  {
935  accum = tree_man->create_unary_operation(type, op0, srcp_default, negate_expr_K);
936  }
937  tem_ga =
938  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
939  block->PushBefore(tem_ga, stmt, AppM);
940  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
941  val_so_far = (val_so_far << log) - 1;
942  break;
943 
944  case alg_add_factor:
945  if(log_node != COST0 && accum != COST0)
946  {
947  tem = tree_man->create_binary_operation(type, accum, log_node, srcp_default, lshift_expr_K);
948  tem_ga =
949  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
950  block->PushBefore(tem_ga, stmt, AppM);
951  tem = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
952  }
953  else
954  {
955  tem = accum;
956  }
957  if(accum != COST0)
958  {
959  accum = tree_man->create_binary_operation(type, accum, tem, srcp_default, plus_expr_K);
960  tem_ga =
961  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
962  block->PushBefore(tem_ga, stmt, AppM);
963  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
964  }
965  else
966  {
967  accum = tem;
968  }
969  val_so_far += val_so_far << log;
970  break;
971 
972  case alg_sub_factor:
973  if(log_node != COST0 && accum != COST0)
974  {
975  tem = tree_man->create_binary_operation(type, accum, log_node, srcp_default, lshift_expr_K);
976  tem_ga =
977  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
978  block->PushBefore(tem_ga, stmt, AppM);
979  tem = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
980  }
981  else
982  {
983  tem = accum;
984  }
985  if(accum != COST0)
986  {
987  accum = tree_man->create_binary_operation(type, tem, accum, srcp_default, minus_expr_K);
988  tem_ga =
989  tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), accum, function_id, srcp_default);
990  block->PushBefore(tem_ga, stmt, AppM);
991  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
992  }
993  else
994  {
995  accum = tem;
996  }
997  val_so_far = (val_so_far << log) - val_so_far;
998  break;
999  case alg_impossible:
1000  case alg_m:
1001  case alg_unknown:
1002  case alg_zero:
1003  default:
1004  THROW_UNREACHABLE("");
1005  }
1006  }
1007 
1008  if(variant == negate_variant)
1009  {
1010 #if HAVE_ASSERTS
1011  val_so_far = -val_so_far;
1012 #endif
1013  tem = tree_man->create_unary_operation(type, accum, srcp_default, negate_expr_K);
1014  tem_ga = tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
1015  block->PushBefore(tem_ga, stmt, AppM);
1016  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
1017  }
1018  else if(variant == add_variant)
1019  {
1020 #if HAVE_ASSERTS
1021  val_so_far = val_so_far + 1;
1022 #endif
1023  tem = tree_man->create_binary_operation(type, accum, op0, srcp_default, plus_expr_K);
1024  tem_ga = tree_man->CreateGimpleAssign(type, tree_nodeRef(), tree_nodeRef(), tem, function_id, srcp_default);
1025  block->PushBefore(tem_ga, stmt, AppM);
1026  accum = GetPointer<gimple_assign>(GET_NODE(tem_ga))->op0;
1027  }
1028 
1031 #if HAVE_ASSERTS
1032  val = val & data_mask;
1033  val_so_far = val_so_far & static_cast<long long int>(data_mask);
1034 #endif
1035  THROW_ASSERT(val == static_cast<unsigned long long int>(val_so_far), "unexpected difference");
1036  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Expanded " + op0->ToString());
1037 
1038  return accum;
1039 }
1040 
1041 tree_nodeRef IR_lowering::expand_smod_pow2(const tree_nodeRef& op0, unsigned long long int d, const tree_nodeRef& stmt,
1042  const blocRef& block, const tree_nodeRef& type,
1043  const std::string& srcp_default)
1044 {
1045  unsigned long long int masklow;
1046  const auto logd = floor_log2(d);
1047  const auto bt = tree_man->GetBooleanType();
1048 
1049  const auto const0 = TM->CreateUniqueIntegerCst(0, type);
1050  const auto constm1 = TM->CreateUniqueIntegerCst(-1, type);
1051  const auto cond_op0 = tree_man->create_binary_operation(bt, op0, const0, srcp_default, lt_expr_K);
1052  const auto signmask_ga = tree_man->CreateGimpleAssign(
1053  bt, TM->CreateUniqueIntegerCst(0, bt), TM->CreateUniqueIntegerCst(1, bt), cond_op0, function_id, srcp_default);
1054  AppM->RegisterTransformation(GetName(), signmask_ga);
1055  block->PushBefore(signmask_ga, stmt, AppM);
1056  const auto cond_expr0 = tree_man->create_ternary_operation(
1057  type, GetPointer<gimple_assign>(GET_NODE(signmask_ga))->op0, constm1, const0, srcp_default, cond_expr_K);
1058 
1059  const auto signmask_condexpr =
1060  tree_man->CreateGimpleAssign(type, nullptr, nullptr, cond_expr0, function_id, srcp_default);
1061 
1062  AppM->RegisterTransformation(GetName(), signmask_condexpr);
1063  block->PushBefore(signmask_condexpr, stmt, AppM);
1064 
1065  auto signmask_var = GetPointer<gimple_assign>(GET_NODE(signmask_condexpr))->op0;
1066  const auto size = tree_helper::Size(type);
1067 
1068  if(logd > 63 || size < logd)
1069  {
1070  THROW_ERROR("unexpected condition");
1071  }
1072  masklow = (1ULL << logd) - 1;
1073  const auto Constmasklow = TM->CreateUniqueIntegerCst(static_cast<long long int>(masklow), type);
1074 
1076  {
1077  auto unsignedType = tree_man->CreateUnsigned(GET_NODE(type));
1078  const auto constshift = TM->CreateUniqueIntegerCst(static_cast<long long>(size - logd), unsignedType);
1079  auto ga_nop = tree_man->CreateNopExpr(signmask_var, unsignedType, tree_nodeRef(), tree_nodeRef(), function_id);
1080  auto nop_vd = GetPointer<gimple_assign>(GET_NODE(ga_nop))->op0;
1081  block->PushBefore(ga_nop, stmt, AppM);
1082  auto temp = tree_man->create_binary_operation(unsignedType, nop_vd, constshift, srcp_default, rshift_expr_K);
1083  auto temp_ga = tree_man->CreateGimpleAssign(unsignedType, nullptr, nullptr, temp, function_id, srcp_default);
1084  AppM->RegisterTransformation(GetName(), temp_ga);
1085  block->PushBefore(temp_ga, stmt, AppM);
1086  nop_vd = GetPointer<gimple_assign>(GET_NODE(temp_ga))->op0;
1087  ga_nop = tree_man->CreateNopExpr(nop_vd, type, tree_nodeRef(), tree_nodeRef(), function_id);
1088  block->PushBefore(ga_nop, stmt, AppM);
1089  signmask_var = GetPointer<gimple_assign>(GET_NODE(ga_nop))->op0;
1090  }
1091  else
1092  {
1093  const auto constshift = TM->CreateUniqueIntegerCst(static_cast<long long>(size - logd), type);
1094  auto temp = tree_man->create_binary_operation(type, signmask_var, constshift, srcp_default, rshift_expr_K);
1095  auto temp_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, temp, function_id, srcp_default);
1096  AppM->RegisterTransformation(GetName(), temp_ga);
1097  block->PushBefore(temp_ga, stmt, AppM);
1098  signmask_var = GetPointer<gimple_assign>(GET_NODE(temp_ga))->op0;
1099  }
1100 
1101  auto temp = tree_man->create_binary_operation(type, op0, signmask_var, srcp_default, plus_expr_K);
1102  auto temp_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, temp, function_id, srcp_default);
1103  AppM->RegisterTransformation(GetName(), temp_ga);
1104  block->PushBefore(temp_ga, stmt, AppM);
1105  auto temp_var = GetPointer<gimple_assign>(GET_NODE(temp_ga))->op0;
1106 
1107  temp = tree_man->create_binary_operation(type, temp_var, Constmasklow, srcp_default, bit_and_expr_K);
1108  temp_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, temp, function_id, srcp_default);
1109  AppM->RegisterTransformation(GetName(), temp_ga);
1110  block->PushBefore(temp_ga, stmt, AppM);
1111  temp_var = GetPointer<gimple_assign>(GET_NODE(temp_ga))->op0;
1112 
1113  return tree_man->create_binary_operation(type, temp_var, signmask_var, srcp_default, minus_expr_K);
1114 }
1115 
1116 tree_nodeRef IR_lowering::expand_sdiv_pow2(const tree_nodeRef& op0, unsigned long long int d, const tree_nodeRef& stmt,
1117  const blocRef& block, const tree_nodeRef& type,
1118  const std::string& srcp_default)
1119 {
1120  const auto logd = floor_log2(d);
1121  const auto bt = tree_man->GetBooleanType();
1122  const auto const0 = TM->CreateUniqueIntegerCst(0, type);
1123 
1124  const auto cond_op0 = tree_man->create_binary_operation(bt, op0, const0, srcp_default, lt_expr_K);
1125  const auto cond_op0_ga = tree_man->CreateGimpleAssign(
1126  bt, TM->CreateUniqueIntegerCst(0, bt), TM->CreateUniqueIntegerCst(1, bt), cond_op0, function_id, srcp_default);
1127  block->PushBefore(cond_op0_ga, stmt, AppM);
1128  const auto cond_op0_ga_var = GetPointer<gimple_assign>(GET_NODE(cond_op0_ga))->op0;
1129  tree_nodeRef t_ga;
1130  tree_nodeRef t2_ga;
1131 
1132  if(d == 2)
1133  {
1134  const auto const1 = TM->CreateUniqueIntegerCst(1, type);
1135  const auto cond_op =
1136  tree_man->create_ternary_operation(type, cond_op0_ga_var, const1, const0, srcp_default, cond_expr_K);
1137  t_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, cond_op, function_id, srcp_default);
1138  block->PushBefore(t_ga, stmt, AppM);
1139  const auto cond_ga_var = GetPointer<gimple_assign>(GET_NODE(t_ga))->op0;
1140 
1141  const auto sum_expr = tree_man->create_binary_operation(type, op0, cond_ga_var, srcp_default, plus_expr_K);
1142  t2_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, sum_expr, function_id, srcp_default);
1143  }
1144  else
1145  {
1146  const auto d_m1 = TM->CreateUniqueIntegerCst(static_cast<long long int>(d - 1), type);
1147  const auto t_expr = tree_man->create_binary_operation(type, op0, d_m1, srcp_default, plus_expr_K);
1148  t_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, t_expr, function_id, srcp_default);
1149  block->PushBefore(t_ga, stmt, AppM);
1150  const auto t_ga_var = GetPointer<gimple_assign>(GET_NODE(t_ga))->op0;
1151 
1152  const auto cond_op =
1153  tree_man->create_ternary_operation(type, cond_op0_ga_var, t_ga_var, op0, srcp_default, cond_expr_K);
1154  t2_ga = tree_man->CreateGimpleAssign(type, nullptr, nullptr, cond_op, function_id, srcp_default);
1155  }
1156  block->PushBefore(t2_ga, stmt, AppM);
1157 
1158  const auto t2_ga_var = GetPointer<gimple_assign>(GET_NODE(t2_ga))->op0;
1159  const auto logdConst = TM->CreateUniqueIntegerCst(static_cast<long long>(logd), type);
1160  return tree_man->create_binary_operation(type, t2_ga_var, logdConst, srcp_default, rshift_expr_K);
1161 }
1162 
1163 tree_nodeRef IR_lowering::expand_MC(const tree_nodeRef& op0, const integer_cst* ic_node, const tree_nodeRef& old_target,
1164  const tree_nodeRef& stmt, const blocRef& block, const tree_nodeRef& type_expr,
1165  const std::string& srcp_default)
1166 {
1167  if(!AppM->ApplyNewTransformation())
1168  {
1169  return old_target;
1170  }
1171  long long int ext_op1 = static_cast<long long>(tree_helper::get_integer_cst_value(ic_node));
1172  short int mult_plus_ratio = 3;
1173  auto data_bitsize = tree_helper::Size(op0);
1174  auto typeSize = tree_helper::Size(type_expr);
1175  if(typeSize < 64)
1176  {
1177  ext_op1 <<= 64 - typeSize;
1178  ext_op1 >>= 64 - typeSize;
1179  }
1180  if(GetPointer<HLS_manager>(AppM))
1181  {
1182  const HLS_deviceRef HLS_D = GetPointer<HLS_manager>(AppM)->get_HLS_device();
1183  bool use64bitMul = false;
1184  if(HLS_D->has_parameter("use_soft_64_mul") && HLS_D->get_parameter<size_t>("use_soft_64_mul"))
1185  {
1186  use64bitMul = true;
1187  }
1188  const technology_managerRef TechManager = HLS_D->get_technology_manager();
1189  auto fu_prec = std::max(8ull, ceil_pow2(data_bitsize));
1190  if(fu_prec >= 64 && use64bitMul)
1191  {
1192  fu_prec = 32;
1193  }
1194  auto component_name_mult =
1195  MULTIPLIER_STD + std::string("_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec) + "_0";
1196  technology_nodeRef mult_f_unit = TechManager->get_fu(component_name_mult, LIBRARY_STD_FU);
1197  THROW_ASSERT(mult_f_unit, "missing component: " + component_name_mult);
1198  auto* mult_fu = GetPointer<functional_unit>(mult_f_unit);
1199  technology_nodeRef mult_op_node = mult_fu->get_operation("mult_expr");
1200  THROW_ASSERT(mult_op_node, "missing mult_expr from " + component_name_mult);
1201  auto* mult_op = GetPointer<operation>(mult_op_node);
1202  double mult_delay = mult_op->time_m->get_execution_time();
1203  auto component_name_add = ADDER_STD + std::string("_") + STR(fu_prec) + "_" + STR(fu_prec) + "_" + STR(fu_prec);
1204  technology_nodeRef add_f_unit = TechManager->get_fu(component_name_add, LIBRARY_STD_FU);
1205  THROW_ASSERT(add_f_unit, "missing component: " + component_name_add);
1206  auto* add_fu = GetPointer<functional_unit>(add_f_unit);
1207  technology_nodeRef add_op_node = add_fu->get_operation("plus_expr");
1208  THROW_ASSERT(add_op_node, "missing plus_expr from " + component_name_add);
1209  auto* add_op = GetPointer<operation>(add_op_node);
1210  double add_delay = add_op->time_m->get_execution_time();
1211  mult_plus_ratio = static_cast<short int>(ceil(mult_delay / add_delay));
1212  }
1213 
1215  if(ext_op1 == 0)
1216  {
1217  return TM->CreateUniqueIntegerCst(0, type_expr);
1218  }
1220  else if(ext_op1 == 1)
1221  {
1222  return op0;
1223  }
1225  else if(ext_op1 == -1)
1226  {
1227  return tree_man->create_unary_operation(type_expr, op0, srcp_default, negate_expr_K);
1228  }
1229  else
1230  {
1231  if(ext_op1 < 0)
1232  {
1233  struct algorithm alg;
1234  enum mult_variant variant;
1235  short int max_cost =
1236  mult_plus_ratio; // static_cast<short
1237  // int>(tree_helper::Size(tree_helper::CGetType(type_expr))/mult_cost_divisor);
1238  if(choose_mult_variant(data_bitsize, -ext_op1, alg, variant, max_cost, TM))
1239  {
1240  tree_nodeRef temp_expr = expand_mult_const(op0, static_cast<unsigned long long int>(-ext_op1), alg, variant,
1241  stmt, block, type_expr, srcp_default);
1242  tree_nodeRef temp_expr_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(),
1243  temp_expr, function_id, srcp_default);
1244  block->PushBefore(temp_expr_ga, stmt, AppM);
1245  tree_nodeRef temp_expr_var = GetPointer<gimple_assign>(GET_NODE(temp_expr_ga))->op0;
1246  return tree_man->create_unary_operation(type_expr, temp_expr_var, srcp_default, negate_expr_K);
1247  }
1248  else
1249  {
1251  return old_target;
1252  }
1253  }
1254  else
1255  {
1256  auto coeff = static_cast<unsigned long long int>(ext_op1);
1257  if(EXACT_POWER_OF_2_OR_ZERO_P(coeff))
1258  {
1259  const auto l_shift = floor_log2(coeff);
1260  const auto l_shift_node = TM->CreateUniqueIntegerCst(static_cast<long long int>(l_shift), type_expr);
1261  return tree_man->create_binary_operation(type_expr, op0, l_shift_node, srcp_default, lshift_expr_K);
1262  }
1263  else
1264  {
1265  struct algorithm alg;
1266  enum mult_variant variant;
1267  short int max_cost =
1268  mult_plus_ratio; // static_cast<short
1269  // int>(tree_helper::Size(tree_helper::CGetType(type_expr))/mult_cost_divisor);
1270 
1271  if(choose_mult_variant(data_bitsize, static_cast<long long int>(coeff), alg, variant, max_cost, TM))
1272  {
1273  return expand_mult_const(op0, coeff, alg, variant, stmt, block, type_expr, srcp_default);
1274  }
1275  else
1276  {
1278  return old_target;
1279  }
1280  }
1281  }
1282  }
1283 }
1284 
1286  const std::string& srcp_default, bool temp_addr)
1287 {
1288  tree_nodeRef accum;
1289  tree_nodeRef type_sum;
1290  unsigned int params = 0;
1291  bool changed = false;
1292 
1293  if(tmr->idx)
1294  {
1295  ++params;
1296  }
1297  if(tmr->step)
1298  {
1299  ++params;
1300  }
1301  if(tmr->offset)
1302  {
1303  ++params;
1304  }
1305  if(tmr->idx2)
1306  {
1307  ++params;
1308  }
1309 
1310  if(params < 1)
1311  {
1312  return changed;
1313  }
1314 
1315  if(tmr->idx)
1316  {
1317  if(tmr->step)
1318  {
1319  auto* ic_step_node = GetPointer<integer_cst>(GET_NODE(tmr->step));
1320  type_sum = ic_step_node->type;
1321  accum = expand_MC(tmr->idx, ic_step_node, tree_nodeRef(), stmt, block, type_sum, srcp_default);
1322  if(accum)
1323  {
1324  tree_nodeRef t_ga = tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), accum,
1325  function_id, srcp_default);
1326  block->PushBefore(t_ga, stmt, AppM);
1327  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(t_ga)->ToString());
1328  accum = GetPointer<gimple_assign>(GET_NODE(t_ga))->op0;
1329  }
1330  else
1331  {
1332  tree_nodeRef t_expr =
1333  tree_man->create_binary_operation(type_sum, tmr->idx, tmr->step, srcp_default, mult_expr_K);
1334  tree_nodeRef t_ga = tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), t_expr,
1335  function_id, srcp_default);
1336  block->PushBefore(t_ga, stmt, AppM);
1337  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(t_ga)->ToString());
1338  accum = GetPointer<gimple_assign>(GET_NODE(t_ga))->op0;
1339  }
1340  tmr->step = tree_nodeRef();
1341  }
1342  else
1343  {
1344  accum = tmr->idx;
1345  }
1346  tmr->idx = tree_nodeRef();
1347  changed = true;
1348  }
1349  if(tmr->offset)
1350  {
1351  if(tree_helper::GetConstValue(tmr->offset) != 0)
1352  {
1353  if(!type_sum)
1354  {
1355  type_sum = tree_man->GetSizeType();
1356  }
1357 
1358  const auto ne = tree_man->create_unary_operation(type_sum, tmr->offset, srcp_default, nop_expr_K);
1359  const auto casted_offset_ga =
1360  tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), ne, function_id, srcp_default);
1361  block->PushBefore(casted_offset_ga, stmt, AppM);
1363  "---adding statement " + GET_NODE(casted_offset_ga)->ToString());
1364  const auto casted_offset_var = GetPointerS<gimple_assign>(GET_NODE(casted_offset_ga))->op0;
1365 
1366  if(accum)
1367  {
1368  const auto t_expr =
1369  tree_man->create_binary_operation(type_sum, casted_offset_var, accum, srcp_default, plus_expr_K);
1370  const auto t_ga = tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), t_expr,
1371  function_id, srcp_default);
1372  block->PushBefore(t_ga, stmt, AppM);
1373  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(t_ga)->ToString());
1374  accum = GetPointerS<gimple_assign>(GET_NODE(t_ga))->op0;
1375  }
1376  else
1377  {
1378  accum = casted_offset_var;
1379  }
1380  }
1381  tmr->offset = tree_nodeRef();
1382  changed = true;
1383  }
1384 
1385  if(tmr->idx2)
1386  {
1387  if(!type_sum)
1388  {
1389  type_sum = tree_man->GetSizeType();
1390  }
1391  auto type_index = tree_helper::get_type_index(TM, GET_INDEX_NODE(tmr->idx2));
1392  if(type_index != GET_INDEX_NODE(type_sum))
1393  {
1394  tree_nodeRef ne = tree_man->create_unary_operation(type_sum, tmr->idx2, srcp_default, nop_expr_K);
1395  tree_nodeRef casted_idx2_ga =
1396  tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), ne, function_id, srcp_default);
1397  block->PushBefore(casted_idx2_ga, stmt, AppM);
1399  "---adding statement " + GET_NODE(casted_idx2_ga)->ToString());
1400  tree_nodeRef casted_idx2_var = GetPointer<gimple_assign>(GET_NODE(casted_idx2_ga))->op0;
1401  if(accum)
1402  {
1403  tree_nodeRef t_expr =
1404  tree_man->create_binary_operation(type_sum, accum, casted_idx2_var, srcp_default, plus_expr_K);
1405  tree_nodeRef t_ga = tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), t_expr,
1406  function_id, srcp_default);
1407  block->PushBefore(t_ga, stmt, AppM);
1408  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(t_ga)->ToString());
1409  accum = GetPointer<gimple_assign>(GET_NODE(t_ga))->op0;
1410  }
1411  else
1412  {
1413  accum = casted_idx2_var;
1414  }
1415  }
1416  else if(accum)
1417  {
1418  tree_nodeRef t_expr = tree_man->create_binary_operation(type_sum, accum, tmr->idx2, srcp_default, plus_expr_K);
1419  tree_nodeRef t_ga =
1420  tree_man->CreateGimpleAssign(type_sum, tree_nodeRef(), tree_nodeRef(), t_expr, function_id, srcp_default);
1421  block->PushBefore(t_ga, stmt, AppM);
1422  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(t_ga)->ToString());
1423  accum = GetPointer<gimple_assign>(GET_NODE(t_ga))->op0;
1424  }
1425  else
1426  {
1427  accum = tmr->idx2;
1428  }
1429  changed = true;
1430  tmr->idx2 = tree_nodeRef();
1431  }
1432 
1433  if(GET_NODE(tmr->base)->get_kind() == addr_expr_K)
1434  {
1435  auto* ae = GetPointer<addr_expr>(GET_NODE(tmr->base));
1436  tree_nodeRef ae_expr = tree_man->create_unary_operation(ae->type, ae->op, srcp_default,
1437  addr_expr_K);
1438  tree_nodeRef ae_ga =
1439  tree_man->CreateGimpleAssign(ae->type, tree_nodeRef(), tree_nodeRef(), ae_expr, function_id, srcp_default);
1440  tree_nodeRef ae_vd = GetPointer<gimple_assign>(GET_NODE(ae_ga))->op0;
1441  GetPointer<gimple_assign>(GET_NODE(ae_ga))->temporary_address = temp_addr;
1442  block->PushBefore(ae_ga, stmt, AppM);
1443  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(ae_ga)->ToString());
1444  tmr->base = ae_vd;
1445  changed = true;
1446  }
1447  if(accum)
1448  {
1449  tree_nodeRef type = tmr->type;
1450  tree_nodeRef pt = tree_man->GetPointerType(type, 8);
1451 
1452  tree_nodeRef ppe_expr =
1453  tree_man->create_binary_operation(pt, tmr->base, accum, srcp_default, pointer_plus_expr_K);
1454  tree_nodeRef ppe_ga =
1455  tree_man->CreateGimpleAssign(pt, tree_nodeRef(), tree_nodeRef(), ppe_expr, function_id, srcp_default);
1456  tree_nodeRef ppe_vd = GetPointer<gimple_assign>(GET_NODE(ppe_ga))->op0;
1457  tmr->base = ppe_vd;
1458  GetPointer<gimple_assign>(GET_NODE(ppe_ga))->temporary_address = temp_addr;
1459  block->PushBefore(ppe_ga, stmt, AppM);
1460  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(ppe_ga)->ToString());
1461  }
1462 
1463  return changed;
1464 }
1465 
1466 tree_nodeRef IR_lowering::expand_mult_highpart(const tree_nodeRef& op0, unsigned long long int ml,
1467  const tree_nodeRef& type_expr, int data_bitsize,
1468  const std::list<tree_nodeRef>::const_iterator it_los,
1469  const blocRef& block, const std::string& srcp_default)
1470 {
1491  int half_data_bitsize = data_bitsize / 2;
1492  tree_nodeRef mask_node =
1493  TM->CreateUniqueIntegerCst(static_cast<long long int>((1LL << half_data_bitsize) - 1), type_expr);
1494  tree_nodeRef half_data_bitsize_node =
1495  TM->CreateUniqueIntegerCst(static_cast<long long int>(half_data_bitsize), type_expr);
1496 
1497  tree_nodeRef u0_expr = tree_man->create_binary_operation(type_expr, op0, mask_node, srcp_default, bit_and_expr_K);
1498  tree_nodeRef u0_ga =
1499  tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u0_expr, function_id, srcp_default);
1500  block->PushBefore(u0_ga, *it_los, AppM);
1501  tree_nodeRef u0_ga_var = GetPointer<gimple_assign>(GET_NODE(u0_ga))->op0;
1502 
1503  tree_nodeRef u1_expr =
1504  tree_man->create_binary_operation(type_expr, op0, half_data_bitsize_node, srcp_default, rshift_expr_K);
1505  tree_nodeRef u1_ga =
1506  tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u1_expr, function_id, srcp_default);
1507  block->PushBefore(u1_ga, *it_los, AppM);
1508  tree_nodeRef u1_ga_var = GetPointer<gimple_assign>(GET_NODE(u1_ga))->op0;
1509 
1510  long long int v0 = static_cast<long long int>(ml) & ((1LL << half_data_bitsize) - 1);
1511  long long int v1;
1512  bool unsignedp = tree_helper::is_unsigned(TM, GET_INDEX_NODE(type_expr));
1513  if(unsignedp)
1514  {
1515  v1 = static_cast<long long int>(ml >> half_data_bitsize);
1516  }
1517  else
1518  {
1519  v1 = static_cast<long long int>(ml) >> half_data_bitsize;
1520  }
1521 
1522  tree_nodeRef u0v0_ga_var;
1523  tree_nodeRef v0_node;
1524  tree_nodeRef v1_node;
1525  if(v0 != 0)
1526  {
1527  if(v0 == 1)
1528  {
1529  u0v0_ga_var = u0_ga_var;
1530  }
1531  else
1532  {
1533  v0_node = TM->CreateUniqueIntegerCst(static_cast<long long int>(v0), type_expr);
1534  tree_nodeRef u0v0_expr =
1535  tree_man->create_binary_operation(type_expr, u0_ga_var, v0_node, srcp_default, mult_expr_K);
1536  tree_nodeRef u0v0_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u0v0_expr,
1537  function_id, srcp_default);
1538  block->PushBefore(u0v0_ga, *it_los, AppM);
1539  u0v0_ga_var = GetPointer<gimple_assign>(GET_NODE(u0v0_ga))->op0;
1540  }
1541  }
1542  tree_nodeRef u0v0h_ga_var;
1543  if(u0v0_ga_var)
1544  {
1545  tree_nodeRef u0v0h_expr = tree_man->create_binary_operation(type_expr, u0v0_ga_var, half_data_bitsize_node,
1546  srcp_default, rshift_expr_K);
1547  tree_nodeRef u0v0h_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u0v0h_expr,
1548  function_id, srcp_default);
1549  block->PushBefore(u0v0h_ga, *it_los, AppM);
1550  u0v0h_ga_var = GetPointer<gimple_assign>(GET_NODE(u0v0h_ga))->op0;
1551  }
1552  tree_nodeRef u0v0hU_ga_var;
1553  if(u0v0h_ga_var && !unsignedp)
1554  {
1555  tree_nodeRef u0v0hU_expr =
1556  tree_man->create_binary_operation(type_expr, u0v0h_ga_var, mask_node, srcp_default, bit_and_expr_K);
1557  tree_nodeRef u0v0hU_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u0v0hU_expr,
1558  function_id, srcp_default);
1559  block->PushBefore(u0v0hU_ga, *it_los, AppM);
1560  u0v0hU_ga_var = GetPointer<gimple_assign>(GET_NODE(u0v0hU_ga))->op0;
1561  }
1562  else
1563  {
1564  u0v0hU_ga_var = u0v0h_ga_var;
1565  }
1566  tree_nodeRef u1v0_ga_var;
1567  if(v0 != 0)
1568  {
1569  if(v0 == 1)
1570  {
1571  u1v0_ga_var = u1_ga_var;
1572  }
1573  else
1574  {
1575  tree_nodeRef u1v0_expr =
1576  tree_man->create_binary_operation(type_expr, u1_ga_var, v0_node, srcp_default, mult_expr_K);
1577  tree_nodeRef u1v0_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u1v0_expr,
1578  function_id, srcp_default);
1579  block->PushBefore(u1v0_ga, *it_los, AppM);
1580  u1v0_ga_var = GetPointer<gimple_assign>(GET_NODE(u1v0_ga))->op0;
1581  }
1582  }
1583  tree_nodeRef u0v0hu1v0_ga_var;
1584  if(u0v0hU_ga_var)
1585  {
1586  THROW_ASSERT(u1v0_ga_var, "unexpected condition");
1587  tree_nodeRef u0v0hu1v0_expr =
1588  tree_man->create_binary_operation(type_expr, u0v0hU_ga_var, u1v0_ga_var, srcp_default, plus_expr_K);
1589  tree_nodeRef u0v0hu1v0_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(),
1590  u0v0hu1v0_expr, function_id, srcp_default);
1591  block->PushBefore(u0v0hu1v0_ga, *it_los, AppM);
1592  u0v0hu1v0_ga_var = GetPointer<gimple_assign>(GET_NODE(u0v0hu1v0_ga))->op0;
1593  }
1594  tree_nodeRef w1_ga_var;
1595  if(u0v0hu1v0_ga_var)
1596  {
1597  tree_nodeRef w1_expr =
1598  tree_man->create_binary_operation(type_expr, u0v0hu1v0_ga_var, mask_node, srcp_default, bit_and_expr_K);
1599  tree_nodeRef w1_ga =
1600  tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), w1_expr, function_id, srcp_default);
1601  block->PushBefore(w1_ga, *it_los, AppM);
1602  w1_ga_var = GetPointer<gimple_assign>(GET_NODE(w1_ga))->op0;
1603  }
1604 
1605  tree_nodeRef w2_ga_var;
1606  if(u0v0hu1v0_ga_var)
1607  {
1608  tree_nodeRef w2_expr = tree_man->create_binary_operation(type_expr, u0v0hu1v0_ga_var, half_data_bitsize_node,
1609  srcp_default, rshift_expr_K);
1610  tree_nodeRef w2_ga =
1611  tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), w2_expr, function_id, srcp_default);
1612  block->PushBefore(w2_ga, *it_los, AppM);
1613  w2_ga_var = GetPointer<gimple_assign>(GET_NODE(w2_ga))->op0;
1614  }
1615 
1616  tree_nodeRef u0v1_ga_var;
1617  if(v1 != 0)
1618  {
1619  if(v1 == 1)
1620  {
1621  u0v1_ga_var = u0_ga_var;
1622  }
1623  else
1624  {
1625  v1_node = TM->CreateUniqueIntegerCst(static_cast<long long int>(v1), type_expr);
1626  tree_nodeRef u0v1_expr =
1627  tree_man->create_binary_operation(type_expr, u0_ga_var, v1_node, srcp_default, mult_expr_K);
1628  tree_nodeRef u0v1_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u0v1_expr,
1629  function_id, srcp_default);
1630  block->PushBefore(u0v1_ga, *it_los, AppM);
1631  u0v1_ga_var = GetPointer<gimple_assign>(GET_NODE(u0v1_ga))->op0;
1632  }
1633  }
1634  tree_nodeRef w1u0v1_ga_var;
1635  if(w1_ga_var)
1636  {
1637  if(u0v1_ga_var)
1638  {
1639  tree_nodeRef w1u0v1_expr =
1640  tree_man->create_binary_operation(type_expr, w1_ga_var, u0v1_ga_var, srcp_default, plus_expr_K);
1641  tree_nodeRef w1u0v1_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), w1u0v1_expr,
1642  function_id, srcp_default);
1643  block->PushBefore(w1u0v1_ga, *it_los, AppM);
1644  w1u0v1_ga_var = GetPointer<gimple_assign>(GET_NODE(w1u0v1_ga))->op0;
1645  }
1646  else
1647  {
1648  w1u0v1_ga_var = w1_ga_var;
1649  }
1650  }
1651  else if(u0v1_ga_var)
1652  {
1653  w1u0v1_ga_var = u0v1_ga_var;
1654  }
1655 
1656  tree_nodeRef w1u0v1h_ga_var;
1657  if(w1u0v1_ga_var)
1658  {
1659  tree_nodeRef w1u0v1h_expr = tree_man->create_binary_operation(type_expr, w1u0v1_ga_var, half_data_bitsize_node,
1660  srcp_default, rshift_expr_K);
1661  tree_nodeRef w1u0v1h_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), w1u0v1h_expr,
1662  function_id, srcp_default);
1663  block->PushBefore(w1u0v1h_ga, *it_los, AppM);
1664  w1u0v1h_ga_var = GetPointer<gimple_assign>(GET_NODE(w1u0v1h_ga))->op0;
1665  }
1666  tree_nodeRef u1v1_ga_var;
1667  if(v1 != 0)
1668  {
1669  if(v1 == 1)
1670  {
1671  u1v1_ga_var = u1_ga_var;
1672  }
1673  else
1674  {
1675  tree_nodeRef u1v1_expr =
1676  tree_man->create_binary_operation(type_expr, u1_ga_var, v1_node, srcp_default, mult_expr_K);
1677  tree_nodeRef u1v1_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), u1v1_expr,
1678  function_id, srcp_default);
1679  block->PushBefore(u1v1_ga, *it_los, AppM);
1680  u1v1_ga_var = GetPointer<gimple_assign>(GET_NODE(u1v1_ga))->op0;
1681  }
1682  }
1683  tree_nodeRef w1u0v1hw2_ga_var;
1684  if(w1u0v1h_ga_var)
1685  {
1686  if(w2_ga_var)
1687  {
1688  tree_nodeRef w1u0v1hw2_expr =
1689  tree_man->create_binary_operation(type_expr, w1u0v1h_ga_var, w2_ga_var, srcp_default, plus_expr_K);
1690  tree_nodeRef w1u0v1hw2_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(),
1691  w1u0v1hw2_expr, function_id, srcp_default);
1692  block->PushBefore(w1u0v1hw2_ga, *it_los, AppM);
1693  w1u0v1hw2_ga_var = GetPointer<gimple_assign>(GET_NODE(w1u0v1hw2_ga))->op0;
1694  }
1695  else
1696  {
1697  w1u0v1hw2_ga_var = w1u0v1h_ga_var;
1698  }
1699  }
1700  else if(w2_ga_var)
1701  {
1702  w1u0v1hw2_ga_var = w2_ga_var;
1703  }
1704 
1705  tree_nodeRef res_ga_var;
1706  if(w1u0v1hw2_ga_var)
1707  {
1708  if(u1v1_ga_var)
1709  {
1710  tree_nodeRef res_expr =
1711  tree_man->create_binary_operation(type_expr, w1u0v1hw2_ga_var, u1v1_ga_var, srcp_default, plus_expr_K);
1712  tree_nodeRef res_ga = tree_man->CreateGimpleAssign(type_expr, tree_nodeRef(), tree_nodeRef(), res_expr,
1713  function_id, srcp_default);
1714  block->PushBefore(res_ga, *it_los, AppM);
1715  res_ga_var = GetPointer<gimple_assign>(GET_NODE(res_ga))->op0;
1716  }
1717  else
1718  {
1719  res_ga_var = w1u0v1hw2_ga_var;
1720  }
1721  }
1722  else if(u1v1_ga_var)
1723  {
1724  res_ga_var = u1v1_ga_var;
1725  }
1726  else
1727  {
1728  res_ga_var = TM->CreateUniqueIntegerCst(static_cast<long long int>(0), type_expr);
1729  }
1730  return res_ga_var;
1731 }
1732 
1733 tree_nodeRef IR_lowering::array_ref_lowering(array_ref* AR, const std::string& srcp_default,
1734  std::pair<unsigned int, blocRef> block,
1735  std::list<tree_nodeRef>::const_iterator it_los, bool temp_addr)
1736 {
1737  tree_nodeRef type = AR->type;
1738 
1739  tree_nodeRef pt = tree_man->GetPointerType(type, GetPointer<type_node>(GET_NODE(type))->algn);
1740  tree_nodeRef ae = tree_man->create_unary_operation(pt, AR->op0, srcp_default, addr_expr_K);
1741  tree_nodeRef ae_ga = tree_man->CreateGimpleAssign(pt, tree_nodeRef(), tree_nodeRef(), ae, function_id, srcp_default);
1742  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(ae_ga)->ToString());
1743  GetPointer<gimple_assign>(GET_NODE(ae_ga))->temporary_address = temp_addr;
1744  tree_nodeRef ae_vd = GetPointer<gimple_assign>(GET_NODE(ae_ga))->op0;
1745  block.second->PushBefore(ae_ga, *it_los, AppM);
1746 
1747  tree_nodeRef offset_type = tree_man->GetSizeType();
1748  auto ar_op1_type_index = tree_helper::CGetType(AR->op1)->index;
1749  tree_nodeRef offset_node;
1750  if(ar_op1_type_index != GET_INDEX_NODE(offset_type))
1751  {
1752  tree_nodeRef ne = tree_man->create_unary_operation(offset_type, AR->op1, srcp_default, nop_expr_K);
1753  tree_nodeRef nop_ga =
1754  tree_man->CreateGimpleAssign(offset_type, tree_nodeRef(), tree_nodeRef(), ne, function_id, srcp_default);
1755  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(nop_ga)->ToString());
1756  offset_node = GetPointer<gimple_assign>(GET_NODE(nop_ga))->op0;
1757  block.second->PushBefore(nop_ga, *it_los, AppM);
1758  }
1759  else
1760  {
1761  offset_node = AR->op1;
1762  }
1763  const auto ar_op0_type_node = tree_helper::CGetType(AR->op0);
1764  THROW_ASSERT(GET_CONST_NODE(ar_op0_type_node)->get_kind() == array_type_K,
1765  "array_type expected: @" + STR(ar_op0_type_node->index));
1766  auto data_bitsize = tree_helper::GetArrayElementSize(ar_op0_type_node);
1767  auto n_byte = compute_n_bytes(data_bitsize);
1768  const auto dims = tree_helper::GetArrayDimensions(ar_op0_type_node);
1769  for(size_t ind = 1; ind < dims.size(); ++ind)
1770  {
1771  n_byte *= dims.at(ind);
1772  }
1773  tree_nodeRef coef_node = TM->CreateUniqueIntegerCst(static_cast<long long>(n_byte), offset_type);
1774  tree_nodeRef m = tree_man->create_binary_operation(offset_type, offset_node, coef_node, srcp_default, mult_expr_K);
1775  tree_nodeRef m_ga =
1776  tree_man->CreateGimpleAssign(offset_type, tree_nodeRef(), tree_nodeRef(), m, function_id, srcp_default);
1777  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(m_ga)->ToString());
1778  tree_nodeRef m_vd = GetPointer<gimple_assign>(GET_NODE(m_ga))->op0;
1779  block.second->PushBefore(m_ga, *it_los, AppM);
1780 
1781  tree_nodeRef pp = tree_man->create_binary_operation(pt, ae_vd, m_vd, srcp_default, pointer_plus_expr_K);
1782  tree_nodeRef pp_ga = tree_man->CreateGimpleAssign(pt, tree_nodeRef(), tree_nodeRef(), pp, function_id, srcp_default);
1783  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---adding statement " + GET_NODE(pp_ga)->ToString());
1784  GetPointer<gimple_assign>(GET_NODE(pp_ga))->temporary_address = temp_addr;
1785  tree_nodeRef pp_vd = GetPointer<gimple_assign>(GET_NODE(pp_ga))->op0;
1786  block.second->PushBefore(pp_ga, *it_los, AppM);
1787 
1789  return tree_man->create_binary_operation(type, pp_vd, offset, srcp_default, mem_ref_K);
1790 }
1791 
1793 {
1794  if(stmt)
1795  {
1796  const auto ga = GetPointer<const gimple_assign>(GET_CONST_NODE(stmt));
1797  if(ga)
1798  {
1799  const auto op0 = GET_CONST_NODE(ga->op0);
1800  const auto op1 = GET_CONST_NODE(ga->op1);
1801  if(op1->get_kind() == cond_expr_K)
1802  {
1803  return false;
1804  }
1805  if(not ga->init_assignment and op0->get_kind() == ssa_name_K and op1->get_kind() == var_decl_K)
1806  {
1807  return false;
1808  }
1809  }
1810  }
1811  if(not AppM->ApplyNewTransformation())
1812  {
1813  return true;
1814  }
1815  return false;
1816 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
This struct specifies the integer_cst node.
Definition: tree_node.hpp:3242
T floor_log2(T x)
Given X, an unsigned number, return the largest int Y such that 2**Y <= X. If X is 0...
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
bool reached_max_transformation_limit(const tree_nodeRef &stmt)
check if the max transformation limit has been reached
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
static std::vector< unsigned long long > GetArrayDimensions(const tree_nodeConstRef &node)
Return the dimension of the array.
static CustomUnorderedMap< std::pair< unsigned int, unsigned long long >, std::pair< enum alg_code, struct mult_cost > > alg_hash
File containing functions and utilities to support the printing of debug messagges.
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
std::string ToString() const
Print this node as string in gimple format.
technology_nodeRef get_fu(const std::string &fu_name, const std::string &Library) const
Return the reference to a component given its name.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
static bool is_unsigned(const tree_managerConstRef &TM, const unsigned int index)
Return true if the treenode is of unsigned integer type.
short latency
Total cost of the multiplication sequence.
Definition of the class representing a generic C application.
refcount< tree_manipulation > tree_manipulationRef
tree_nodeRef idx
INDEX register.
Definition: tree_node.hpp:4955
std::string GetName() const override
Return the name of this design step.
tree_nodeRef expand_mult_const(const tree_nodeRef &op0, unsigned long long int val, const struct algorithm &alg, enum mult_variant &variant, const tree_nodeRef &stmt, const blocRef &block, const tree_nodeRef &type, const std::string &srcp_default)
A subroutine of expand_mult, used for constant multiplications.
tree_nodeRef CreateUnsigned(const tree_nodeConstRef &signed_type) const
Create an unsigned integer type starting from signed type.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
mathematical utility function not provided by standard libraries
tree_nodeRef GetSizeType() const
create a sizetype builtin type in case it has not already been created, otherwise it returns the one ...
This structure records a sequence of operations.
Class specification of the graph structures.
exceptions managed by PandA
tree_nodeRef create_binary_operation(const tree_nodeConstRef &type, const tree_nodeRef &op0, const tree_nodeRef &op1, const std::string &srcp, enum kind operation_kind) const
Function used to create a binary expression.
G get_parameter(const std::string &key) const
Returns a parameter by key.
IR_lowering(const ParameterConstRef Param, const application_managerRef AppM, unsigned int function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
Definition: IR_lowering.cpp:82
Collect information about resource performance.
T exact_log2(T x)
Return the logarithm of X, base 2, considering X unsigned, if X is a power of 2.
static unsigned long long GetArrayElementSize(const tree_nodeConstRef &node)
Return the size (in bits) of the base element of the array.
#define CHEAPER_MULT_COST(X, Y)
This macro is used to compare two mult_costs against each other.
const CustomUnorderedSet< std::pair< FrontendFlowStepType, FunctionRelationship > > ComputeFrontendRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
Definition: IR_lowering.cpp:90
tree_nodeRef base
BASE register.
Definition: tree_node.hpp:4949
#define GET_INDEX_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:361
#define LIBRARY_STD_FU
standard library where all standard HLS resources are defined
char log[64]
#define min(x, y)
Class specification of the manager of the technology library data structures.
tree_nodeRef expand_MC(const tree_nodeRef &op0, const integer_cst *ic_node, const tree_nodeRef &old_target, const tree_nodeRef &stmt, const blocRef &block, const tree_nodeRef &type_expr, const std::string &srcp_default)
Data structure describing a basic block at tree level.
static unsigned int get_type_index(const tree_managerConstRef &TM, const unsigned int index, long long int &vec_size, bool &is_a_pointer, bool &is_a_function)
Return the treenode index of the type of index.
redefinition of map to manage ordered/unordered structures
tree_nodeRef create_unary_operation(const tree_nodeConstRef &type, const tree_nodeRef &op, const std::string &srcp, enum kind operation_kind) const
EXPRESSION_TREE_NODES.
tree_nodeRef CreateGimpleAssign(const tree_nodeConstRef &type, const tree_nodeConstRef &min, const tree_nodeConstRef &max, const tree_nodeRef &op, unsigned int function_decl_nid, const std::string &srcp) const
Create gimple assignment.
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
static bool IsUnsignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of unsigned integer type.
#define MULT_COST_LESS(X, Y)
This macro is used to compare a pointer to a mult_cost against an single integer "cost" value...
#define ASSERT_PARAMETER(parameter)
Definition: utility.hpp:96
Pure virtual base class for all the design flow step factory.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
#define EXACT_POWER_OF_2_OR_ZERO_P(x)
Test whether a value is zero of a power of two.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
tree_nodeRef GetPointerType(const tree_nodeConstRef &ptd, unsigned long long algn=0) const
Function that creates a pointer type if it is not already present, otherwise it returns the one that ...
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
tree_managerRef TM
The tree manager.
Definition: IR_lowering.hpp:88
This C++ header file contains common macros for the tree structure.
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
mult_variant
Indicates the type of fixup needed after a constant multiplication.
Definition: IR_lowering.hpp:74
Class specification of the data structures used to manage technology information. ...
static integer_cst_t get_integer_cst_value(const integer_cst *ic)
Convert a integer_cst in a long long value.
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
Low-level memory addressing.
Definition: tree_node.hpp:4938
Classes to describe design flow graph.
tree_nodeRef CreateUniqueIntegerCst(integer_cst_t value, const tree_nodeConstRef &type)
memoization of integer constants
static const std::string ComputeSignature(const TechnologyFlowStep_Type technology_flow_step_type)
Compute the signature of a technology flow step.
Factory for technology flow step.
struct mult_cost cost
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
unsigned offset[NUM_VERTICES+1]
Definition: graph.h:3
tree_nodeRef step
STEP integer constant.
Definition: tree_node.hpp:4958
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
tree_nodeRef expand_smod_pow2(const tree_nodeRef &op0, unsigned long long int d, const tree_nodeRef &stmt, const blocRef &block, const tree_nodeRef &type, const std::string &srcp_default)
Expand signed modulus of OP0 by a power of two D in mode MODE.
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Wrapper of design_flow.
enum alg_code op[64]
bool expand_target_mem_ref(target_mem_ref461 *tmr, const tree_nodeRef &stmt, const blocRef &block, const std::string &srcp_default, bool temp_addr)
tree_nodeRef GetBooleanType() const
Function that creates a boolean type if it is not already present, otherwise it returns the one that ...
T compute_n_bytes(T bitsize)
This struct specifies the block node.
Definition: tree_node.hpp:1820
This file collects some utility functions.
tree_manipulationRef tree_man
The IR manipulation.
Definition: IR_lowering.hpp:91
alg_code
the code for lowering of div, mult and rem comes from GCC sources (expmed.c)
tree_nodeRef type
type of the expression
Definition: tree_node.hpp:4946
refcount< T > lock() const
Definition: refcount.hpp:212
tree_nodeRef create_ternary_operation(const tree_nodeConstRef &type, const tree_nodeRef &op0, const tree_nodeRef &op1, const tree_nodeRef &op2, const std::string &srcp, enum kind operation_kind) const
Function used to create a ternary expression.
const unsigned int function_id
The index of the function to be analyzed.
const application_managerRef AppM
The application manager.
Class specification of the tree_reindex support class.
tree_nodeRef expand_mult_highpart(const tree_nodeRef &op0, unsigned long long int ml, const tree_nodeRef &type_expr, int data_bitsize, const std::list< tree_nodeRef >::const_iterator it_los, const blocRef &block, const std::string &srcp_default)
Decompose some complex gimple statements into set of simple operations.
bool has_parameter(const std::string &key) const
Check if parameter exist.
technology_managerRef get_technology_manager() const
Returns the technology manager.
tree_nodeRef expand_sdiv_pow2(const tree_nodeRef &op0, unsigned long long int d, const tree_nodeRef &stmt, const blocRef &block, const tree_nodeRef &type, const std::string &srcp_default)
Expand signed division of OP0 by a power of two D in mode MODE.
tree_nodeRef array_ref_lowering(array_ref *AR, const std::string &srcp_default, std::pair< unsigned int, blocRef > block, std::list< tree_nodeRef >::const_iterator it_los, bool temp_addr)
This file collects some hash functors.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
tree_nodeRef CreateNopExpr(const tree_nodeConstRef &operand, const tree_nodeConstRef &type, const tree_nodeConstRef &min, const tree_nodeConstRef &max, unsigned int function_decl_nid) const
Create a nop_expr to perform a conversion.
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
#define ADDER_STD
static void synth_mult(struct algorithm &alg_out, unsigned long long t, const struct mult_cost &cost_limit, unsigned long long data_bitsize, tree_managerRef &TM)
Compute and return the best algorithm for multiplying by T.
tree_nodeRef idx2
INDEX register.
Definition: tree_node.hpp:4961
this class is used to manage the command-line or XML options.
refcount< tree_node > tree_nodeRef
RefCount type definition of the tree_node class structure.
Definition: tree_node.hpp:212
This structure holds the "cost" of a multiply sequence.
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
int debug_level
The debug level.
#define MULTIPLIER_STD
~IR_lowering() override
Destructor.
static bool choose_mult_variant(unsigned long long data_bitsize, long long int val, struct algorithm &alg, enum mult_variant &variant, short int Mult_cost, tree_managerRef &TM)
Find the cheapest way of multiplying a value of mode MODE by VAL.
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
tree_nodeRef offset
OFFSET integer constant.
Definition: tree_node.hpp:4952
Class specification of the manager of the tree structures extracted from the raw file.
Base class for technology flow steps.
HLS specialization of generic_device.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:52 for PandA-2024.02 by doxygen 1.8.13