PandA-2024.02
lut_transformation.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) 2019-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  */
42 #include "lut_transformation.hpp"
43 
44 #pragma GCC diagnostic push
45 #pragma GCC diagnostic ignored "-Wswitch-enum"
46 #define USE_SAT 0
47 #pragma region needed by mockturtle / algorithms / satlut_mapping.hpp
48 #define LIN64
49 #define ABC_NAMESPACE pabc
50 #define ABC_NO_USE_READLINE
51 #pragma endregion
52 #define FMT_HEADER_ONLY 1
53 #define PHMAP_BIDIRECTIONAL 0
54 #define MCDBGQ_NOLOCKFREE_FREELIST 0
55 #define MCDBGQ_TRACKMEM 0
56 #define MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX 0
57 #define MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH 0
58 #define MCDBGQ_USEDEBUGFREELIST 0
59 #define DISABLE_NAUTY
60 #define MIG_SYNTHESIS 0
61 
62 #include <kitty/print.hpp>
63 #include <mockturtle/algorithms/aig_resub.hpp>
64 #include <mockturtle/algorithms/balancing.hpp>
65 #include <mockturtle/algorithms/balancing/sop_balancing.hpp>
66 #include <mockturtle/algorithms/cleanup.hpp>
67 #include <mockturtle/algorithms/collapse_mapped.hpp>
68 #include <mockturtle/algorithms/cut_rewriting.hpp>
69 #include <mockturtle/algorithms/functional_reduction.hpp>
70 #include <mockturtle/algorithms/lut_mapping.hpp>
71 #include <mockturtle/algorithms/node_resynthesis.hpp>
72 #include <mockturtle/algorithms/node_resynthesis/bidecomposition.hpp>
73 #include <mockturtle/algorithms/node_resynthesis/dsd.hpp>
74 #include <mockturtle/algorithms/node_resynthesis/shannon.hpp>
75 #include <mockturtle/algorithms/node_resynthesis/xag_npn.hpp>
76 #include <mockturtle/algorithms/refactoring.hpp>
77 #include <mockturtle/generators/arithmetic.hpp>
78 #include <mockturtle/io/write_bench.hpp>
79 #include <mockturtle/networks/aig.hpp>
80 #include <mockturtle/networks/klut.hpp>
81 #include <mockturtle/views/mapping_view.hpp>
82 #include <type_traits>
83 #if MIG_SYNTHESIS
84 #include <mockturtle/algorithms/mig_algebraic_rewriting.hpp>
85 #include <mockturtle/algorithms/node_resynthesis/mig_npn.hpp>
86 #endif
87 #if USE_SAT
88 #include <mockturtle/algorithms/satlut_mapping.hpp>
89 #endif
90 
91 #include "Parameter.hpp"
92 #include "allocation_constants.hpp"
93 #include "application_manager.hpp"
94 #include "behavioral_helper.hpp"
95 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_
96 #include "design_flow_graph.hpp"
97 #include "design_flow_manager.hpp"
98 #include "function_behavior.hpp"
99 #include "hls_device.hpp"
100 #include "hls_manager.hpp"
101 #include "math_function.hpp"
102 #include "string_manipulation.hpp" // for GET_CLASS
103 #include "technology_flow_step.hpp"
105 #include "technology_manager.hpp"
106 #include "technology_node.hpp"
107 #include "time_info.hpp"
108 #include "tree_basic_block.hpp"
109 #include "tree_helper.hpp"
110 #include "tree_manager.hpp"
111 #include "tree_manipulation.hpp"
112 #include "tree_reindex.hpp"
113 #include <fstream>
114 
115 #pragma region Macros declaration
116 
118 {
119  auto b0 = tree_helper::CGetType(be->op0);
122  {
123  return false;
124  }
125  auto b1 = tree_helper::CGetType(be->op1);
128  {
129  return false;
130  }
132  {
133  return false;
134  }
135  return tree_helper::Size(be->op0) == 1 && tree_helper::Size(be->op1) == 1;
136 }
138 {
139  auto b0 = tree_helper::CGetType(be->op0);
142  {
143  return false;
144  }
145  auto b1 = tree_helper::CGetType(be->op1);
148  {
149  return false;
150  }
151  bool is_simple_case = [&]() -> bool {
152  if(GET_CONST_NODE(be->op1)->get_kind() != integer_cst_K)
153  {
154  return false;
155  }
156  const auto cst_val = tree_helper::GetConstValue(be->op1);
157  auto k = be->get_kind();
158  return (k == lt_expr_K || k == gt_expr_K) && cst_val == 0;
159  }();
160  return (tree_helper::Size(be->op0) <= max && tree_helper::Size(be->op1) <= max) ||
161  (is_simple_case && !parameters->isOption(OPT_context_switch));
162 }
164 {
165  auto c0 = tree_helper::CGetType(ce->op1);
168  {
169  return false;
170  }
171  auto c1 = tree_helper::CGetType(ce->op2);
174  {
175  return false;
176  }
178  {
179  return false;
180  }
181  return tree_helper::Size(ce->op1) == 1 && tree_helper::Size(ce->op2) == 1;
182 }
184 {
185  auto c0 = tree_helper::CGetType(ne->op);
188  {
189  return false;
190  }
192  {
193  return false;
194  }
195  return tree_helper::Size(ne->op) == 1;
196 }
197 
198 #define VECT_CONTAINS(v, x) (std::find((v).begin(), (v).end(), x) != (v).end())
199 
201 {
202  auto op_node = GET_NODE(op);
203  auto code = op_node->get_kind();
204 
205  return !(GetPointer<lut_expr>(op_node) ||
206  (GetPointer<truth_not_expr>(op_node) && CHECK_NOT_EXPR_SIZE(GetPointer<truth_not_expr>(op_node))) ||
207  (GetPointer<bit_not_expr>(op_node) && CHECK_NOT_EXPR_SIZE(GetPointer<bit_not_expr>(op_node))) ||
208  (GetPointer<cond_expr>(op_node) && CHECK_COND_EXPR_SIZE(GetPointer<cond_expr>(op_node))) ||
209  (VECT_CONTAINS(lutBooleanExpressibleOperations, code) && GetPointer<binary_expr>(op_node) &&
210  CHECK_BIN_EXPR_BOOL_SIZE(GetPointer<binary_expr>(op_node))) ||
211  (VECT_CONTAINS(lutIntegerExpressibleOperations, code) && GetPointer<binary_expr>(op_node) &&
212  CHECK_BIN_EXPR_INT_SIZE(GetPointer<binary_expr>(op_node),
213  parameters->GetParameter<unsigned int>("MAX_LUT_INT_SIZE"))));
214 }
215 
216 #pragma endregion
217 
218 #pragma region Types declaration
219 
223 class klut_network_ext : public mockturtle::klut_network
224 {
225  private:
226  void fix_inputs_size(std::vector<signal>* a, std::vector<signal>* b, bool signedValues)
227  {
228  if(a->size() > b->size())
229  {
230  auto msbPos = b->size() - 1;
231  auto niter = a->size() - b->size();
232  for(size_t i = 0; i < niter; ++i)
233  {
234  if(signedValues)
235  {
236  b->push_back(b->at(msbPos));
237  }
238  else
239  {
240  b->push_back(this->get_constant(false));
241  }
242  }
243  }
244  else if(a->size() < b->size())
245  {
246  auto msbPos = a->size() - 1;
247  auto niter = b->size() - a->size();
248  for(size_t i = 0; i < niter; ++i)
249  {
250  if(signedValues)
251  {
252  a->push_back(a->at(msbPos));
253  }
254  else
255  {
256  a->push_back(this->get_constant(false));
257  }
258  }
259  }
260  }
261 
262  kitty::dynamic_truth_table create_lt_tt(unsigned int bits)
263  {
264  kitty::dynamic_truth_table tt(bits * 2);
265  kitty::clear(tt);
266 
267  for(unsigned int i = 0; i < bits; ++i)
268  {
269  for(unsigned int j = i + 1; j < bits; ++j)
270  {
271  kitty::set_bit(tt, j + i * bits);
272  }
273  }
274 
275  return tt;
276  }
277 
278  public:
279 #pragma region single - bit operations
280 
288  signal create_ge(signal const a, signal const b)
289  {
290  return this->create_not(this->create_lt(a, b));
291  }
292 
301  signal create_gt(signal const a, signal const b)
302  {
303  return this->create_not(this->create_le(a, b));
304  }
305 
314  signal create_eq(signal const a, signal const b)
315  {
316  return this->create_not(this->create_xor(a, b));
317  }
318 
327  signal create_ne(signal const a, signal const b)
328  {
329  return this->create_xor(a, b);
330  }
331 #pragma endregion
332 
333 #pragma region utilities
334 
335  std::vector<signal> create_pi_v(size_t size)
336  {
337  std::vector<signal> pis(size);
338 
339  for(size_t i = 0; i < size; ++i)
340  {
341  pis[i] = create_pi();
342  }
343 
344  return pis;
345  }
346 
347  void create_po_v(std::vector<signal> pos)
348  {
349  for(size_t i = 0; i < pos.size(); ++i)
350  {
351  create_po(pos[i]);
352  }
353  }
354 
355  std::vector<signal> get_constant_v(std::vector<bool> bits)
356  {
357  std::vector<signal> outputs;
358  for(auto b : bits)
359  {
360  outputs.push_back(b == false ? this->get_constant(false) : this->create_not(this->get_constant(false)));
361  }
362 
363  return outputs;
364  }
365 
375  signal create_lut(std::vector<signal> s, long long f)
376  {
377  if(f == -1LL)
378  {
379  return this->create_not(this->get_constant(false));
380  }
381  kitty::dynamic_truth_table tt(static_cast<unsigned>(s.size()));
382  std::stringstream resHex;
383  resHex << std::hex << static_cast<unsigned long long>(f);
384  std::string res0 = resHex.str();
385  if(tt.num_vars() > 1)
386  {
387  while((res0.size() << 2) < tt.num_bits())
388  {
389  res0 = "0" + res0;
390  }
391  }
392  while((res0.size() << 2) > tt.num_bits() && tt.num_vars() > 1)
393  {
394  res0 = res0.substr(1);
395  }
396 
397  kitty::create_from_hex_string(tt, res0);
398  return create_node(s, tt);
399  }
400 
401 #pragma endregion
402 
403 #pragma region multi - bit operations
404 
405  std::vector<signal> create_buf_v(std::vector<signal> const& a)
406  {
407  return a;
408  }
409 
410  std::vector<signal> create_not_v(std::vector<signal> const& a)
411  {
412  std::vector<signal> outputs;
413  for(auto s : a)
414  {
415  outputs.push_back(this->create_not(s));
416  }
417  return outputs;
418  }
419 
420  std::vector<signal> create_and_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
421  {
422  std::vector<signal> a_c(a), b_c(b);
423  this->fix_inputs_size(&a_c, &b_c, signedValues);
424 
425  std::vector<signal> outputs;
426  outputs.reserve(a_c.size());
427  std::transform(a_c.begin(), a_c.end(), b_c.begin(), std::back_inserter(outputs),
428  [&](auto const& s1, auto const& s2) { return this->create_and(s1, s2); });
429 
430  return outputs;
431  }
432 
433  std::vector<signal> create_or_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
434  {
435  std::vector<signal> a_c(a), b_c(b);
436  this->fix_inputs_size(&a_c, &b_c, signedValues);
437 
438  std::vector<signal> outputs;
439  outputs.reserve(a_c.size());
440  std::transform(a_c.begin(), a_c.end(), b_c.begin(), std::back_inserter(outputs),
441  [&](auto const& s1, auto const& s2) { return this->create_or(s1, s2); });
442 
443  return outputs;
444  }
445 
446  std::vector<signal> create_xor_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
447  {
448  std::vector<signal> a_c(a), b_c(b);
449  this->fix_inputs_size(&a_c, &b_c, signedValues);
450 
451  std::vector<signal> outputs;
452  outputs.reserve(a_c.size());
453  std::transform(a_c.begin(), a_c.end(), b_c.begin(), std::back_inserter(outputs),
454  [&](auto const& s1, auto const& s2) { return this->create_xor(s1, s2); });
455 
456  return outputs;
457  }
458 
459  std::vector<signal> create_lt_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
460  {
461  std::vector<signal> a_c(a), b_c(b);
462  this->fix_inputs_size(&a_c, &b_c, signedValues);
463 
464  if(!signedValues)
465  {
466  a_c.push_back(this->get_constant(false));
467  b_c.push_back(this->get_constant(false));
468  }
469  a_c.push_back(a_c.at(a_c.size() - 1));
470  b_c.push_back(b_c.at(b_c.size() - 1));
471 
472  signal cbit = this->create_not(this->get_constant(false));
473  signal neg1, result = this->get_constant(false);
474  for(auto column = 0u; column < a_c.size(); ++column)
475  {
476  neg1 = this->create_not(b_c.at(column));
477  std::tie(result, cbit) = mockturtle::full_adder(*this, a_c.at(column), neg1, cbit);
478  }
479  return {result};
480  }
481 
482  std::vector<signal> create_ge_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
483  {
484  auto lt_res = this->create_lt_v(a, b, signedValues);
485  return {this->create_not(lt_res.at(0))};
486  }
487 
488  std::vector<signal> create_gt_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
489  {
490  return this->create_lt_v(b, a, signedValues);
491  }
492 
493  std::vector<signal> create_le_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
494  {
495  return this->create_ge_v(b, a, signedValues);
496  }
497 
498  std::vector<signal> create_eq_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
499  {
500  std::vector<signal> a_c(a), b_c(b);
501  this->fix_inputs_size(&a_c, &b_c, signedValues);
502 
503  std::vector<signal> outputs;
504  outputs.reserve(a_c.size());
505  std::transform(a_c.begin(), a_c.end(), b_c.begin(), std::back_inserter(outputs),
506  [&](auto const& s1, auto const& s2) { return this->create_eq(s1, s2); });
507 
508  return {this->create_nary_and(outputs)};
509  }
510 
511  std::vector<signal> create_ne_v(std::vector<signal> const& a, std::vector<signal> const& b, bool signedValues)
512  {
513  return this->create_not_v(this->create_eq_v(a, b, signedValues));
514  }
515 
516 #pragma endregion
517 };
518 
523 {
525  uint64_t index;
526 
528  long long lut_constant;
529 
531  std::vector<uint64_t> fan_in;
532 
534  bool is_po;
535 
537  uint64_t po_index;
538 
541  explicit klut_network_node(uint64_t _index, long long _lut_constant, const std::vector<uint64_t>& _fan_in,
542  bool _is_po, uint64_t _po_index, bool _is_constant)
543  : index(_index),
544  lut_constant(_lut_constant),
545  fan_in(_fan_in),
546  is_po(_is_po),
547  po_index(_po_index),
548  is_constant(_is_constant)
549  {
550  }
551 };
552 
557 using klut_network_fn = mockturtle::klut_network::signal (klut_network_ext::*)(const mockturtle::klut_network::signal,
558  const mockturtle::klut_network::signal);
559 
564 using klut_network_fn_v = std::vector<mockturtle::klut_network::signal> (klut_network_ext::*)(
565  const std::vector<mockturtle::klut_network::signal>&, const std::vector<mockturtle::klut_network::signal>&, bool);
566 
567 #pragma endregion
568 
574 bool lut_transformation::CheckIfPI(tree_nodeRef in, unsigned int BB_index)
575 {
576  auto ssa = GetPointer<ssa_name>(GET_NODE(in));
577  if(!ssa)
578  {
579  THROW_ERROR("expected as in a ssa variable");
580  }
581  tree_nodeRef def_stmt = GET_NODE(ssa->CGetDefStmt());
582  if(def_stmt->get_kind() != gimple_assign_K)
583  {
584  return true;
585  }
586  auto* gaDef = GetPointer<gimple_assign>(def_stmt);
587  if(gaDef->bb_index != BB_index)
588  {
589  return true;
590  }
591  return cannotBeLUT(gaDef->op1);
592 }
593 
602 bool lut_transformation::CheckIfProcessable(std::pair<unsigned int, blocRef> block)
603 {
604  for(const auto& statement : block.second->CGetStmtList())
605  {
606  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Analyzing CheckIfProcessable" + statement->ToString());
607  // only gimple assignments are considered
608  if(GET_NODE(statement)->get_kind() != gimple_assign_K)
609  {
610  continue;
611  }
612 
613  auto* gimpleAssign = GetPointer<gimple_assign>(GET_NODE(statement));
614  enum kind code = GET_NODE(gimpleAssign->op1)->get_kind();
615 
616  if(code == lut_expr_K)
617  { // check if it has constant inputs
618  auto* lut = GetPointer<lut_expr>(GET_NODE(gimpleAssign->op1));
619 
620  // cycle for each inputs (op0 is the constant)
621  for(auto node : {lut->op1, lut->op2, lut->op3, lut->op4, lut->op5, lut->op6, lut->op7, lut->op8})
622  {
623  // if the node is null then there are no more inputs
624  if(!node)
625  {
626  break;
627  }
628 
629  // if the node can be converted into an `integer_cst` then the lut as constant inputs
630  if(GetPointer<integer_cst>(GET_NODE(node)))
631  {
633  "---CheckIfProcessable: lut with a constant input returns true");
634  return true;
635  }
636  }
637  }
638  else if(not cannotBeLUT(gimpleAssign->op1))
639  {
641  "---CheckIfProcessable: " + GET_NODE(gimpleAssign->op1)->get_kind_text() + " can be a LUT");
642  return true;
643  }
644  }
645  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---CheckIfProcessable: false");
646 
647  return false;
648 }
649 
657 {
659  const unsigned int currentBBIndex = gimpleAssign->bb_index;
660  // the variables that uses the result of the provided `gimpleAssign`
661  const auto op0 = GET_NODE(gimpleAssign->op0);
662  auto ssa0 = GetPointer<ssa_name>(op0);
663  THROW_ASSERT(ssa0, "unexpected condition");
664  const auto usedIn = ssa0->CGetUseStmts();
665 
666  for(auto node : usedIn)
667  {
668  auto* childGimpleNode = GetPointer<gimple_node>(GET_NODE(node.first));
669  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Analyzing use " + childGimpleNode->ToString());
670  THROW_ASSERT(childGimpleNode, "unexpected condition");
671 
672  // the current operation is a primary output if it is used in
673  // operation not belonging to the current basic block or if the operation
674  // in which it is used does cannot be a LUT
675  if(childGimpleNode->bb_index != currentBBIndex)
676  {
677  return true;
678  }
679  else
680  {
681  auto* childGimpleAssign = GetPointer<gimple_assign>(GET_NODE(node.first));
682  if(!childGimpleAssign)
683  {
684  return true;
685  }
686  if(cannotBeLUT(childGimpleAssign->op1))
687  {
688  return true;
689  }
690  }
691  }
692  return false;
693 }
694 
696 {
697  switch(code)
698  {
699  case bit_and_expr_K:
700  case truth_and_expr_K:
701  return &klut_network_ext::create_and;
702  case bit_ior_expr_K:
703  case truth_or_expr_K:
704  case truth_orif_expr_K:
705  return &klut_network_ext::create_or;
706  case bit_xor_expr_K:
707  case truth_xor_expr_K:
708  return &klut_network_ext::create_xor;
709  case eq_expr_K:
711  case ge_expr_K:
713  case gt_expr_K:
715  case le_expr_K:
716  return &klut_network_ext::create_le;
717  case lt_expr_K:
718  return &klut_network_ext::create_lt;
719  case ne_expr_K:
721  default:
722  return nullptr;
723  }
724 }
725 
726 static std::vector<bool> IntegerToBitArray(integer_cst_t n, size_t size)
727 {
728  const auto oldbits = [&]() {
729  std::vector<bool> bits;
730  for(size_t i = 0; i < size; ++i)
731  {
732  bits.push_back((static_cast<unsigned long long int>(n) & (1ULL << i)) ? true : false);
733  }
734  return bits;
735  }();
736  std::vector<bool> bits;
737  for(size_t i = 0; i < size; ++i)
738  {
739  bits.push_back((n & (integer_cst_t(1) << i)) ? true : false);
740  }
741  THROW_ASSERT(bits == oldbits, "Bits for " + STR(n) + " was " + container_to_string(oldbits, "") + " now is " +
742  container_to_string(bits, ""));
743  return bits;
744 }
745 
747  std::vector<tree_nodeRef>& prev_stmts_to_add)
748 {
749  const auto indexType = tree_man->GetUnsignedLongLongType();
750  tree_nodeRef bit_pos_constant = TM->CreateUniqueIntegerCst(index, indexType);
751  const std::string srcp_default("built-in:0:0");
752  tree_nodeRef eb_op = tree_man->create_extract_bit_expr(source, bit_pos_constant, srcp_default);
753  auto boolType = tree_man->GetBooleanType();
754  tree_nodeRef eb_ga =
755  tree_man->CreateGimpleAssign(boolType, TM->CreateUniqueIntegerCst(0, boolType),
756  TM->CreateUniqueIntegerCst(1, boolType), eb_op, function_id, srcp_default);
757  prev_stmts_to_add.push_back(eb_ga);
758  return GetPointer<const gimple_assign>(GET_CONST_NODE(eb_ga))->op0;
759 }
760 
762 {
763  switch(code)
764  {
765  case eq_expr_K:
767  case ne_expr_K:
769  case le_expr_K:
771  case lt_expr_K:
773  case ge_expr_K:
775  case gt_expr_K:
777  default:
778  return nullptr;
779  }
780 }
781 
782 #ifndef NDEBUG
783 static std::string ConvertBitsToString(const std::vector<bool>& bits, const std::string& true_string = "vdd",
784  const std::string& false_string = "gnd", const std::string& sep = ", ")
785 {
786  std::string s;
787 
788  for(size_t i = 0; i < bits.size(); ++i)
789  {
790  if(i != 0)
791  {
792  s += sep;
793  }
794  s += bits[i] ? true_string : false_string;
795  }
796 
797  return s;
798 }
799 #endif
800 
801 template <typename T>
802 static T ConvertHexToNumber(const std::string& hex0)
803 {
804  uint64_t x;
805  std::stringstream ss;
806  ss << std::hex << hex0;
807  ss >> x;
808 
809  return T(x);
810 }
811 
812 static void ParseKLutNetwork(const mockturtle::klut_network& klut, std::vector<klut_network_node>& luts)
813 {
814  std::map<mockturtle::klut_network::node, CustomOrderedSet<unsigned>> po_set;
815 
816  mockturtle::topo_view ntk_topo{klut};
817 
818  ntk_topo.foreach_po([&](auto const& s, auto i) { po_set[s].insert(i); });
819 
820  ntk_topo.foreach_node([&](const auto& node) {
821  if(ntk_topo.is_pi(node) || ntk_topo.is_constant(node))
822  {
823  return; // continue
824  }
825  auto func = ntk_topo.node_function(node);
826 
827  std::vector<uint64_t> fanIns;
828  ntk_topo.foreach_fanin(node, [&](auto const& fanin_node, auto) { fanIns.push_back(fanin_node); });
829  auto LUT_func = ConvertHexToNumber<long long>(kitty::to_hex(func));
830  auto is_zero = LUT_func == 0;
831  if(!is_zero)
832  {
833  if(po_set.find(node) != po_set.end())
834  {
835  for(auto po_i : po_set.find(node)->second)
836  {
837  klut_network_node lut_node(node, LUT_func, fanIns, true, po_i, false);
838  luts.push_back(lut_node);
839  }
840  }
841  else
842  {
843  klut_network_node lut_node(node, LUT_func, fanIns, false, 0, false);
844  luts.push_back(lut_node);
845  }
846  }
847  });
848 
849  ntk_topo.foreach_po([&](auto const& s, auto i) {
850  if(ntk_topo.is_constant(ntk_topo.get_node(s)))
851  {
852  std::vector<uint64_t> fanIns;
853  klut_network_node lut_node(
854  s, static_cast<long long>(ntk_topo.constant_value(ntk_topo.get_node(s)) ^ ntk_topo.is_complemented(s)),
855  fanIns, true, i, true);
856  luts.push_back(lut_node);
857  }
858  else
859  {
860  auto func = ntk_topo.node_function(s);
861  auto LUT_func = ConvertHexToNumber<uint64_t>(kitty::to_hex(func));
862  auto is_zero = LUT_func == 0;
863  if(is_zero)
864  {
865  std::vector<uint64_t> fanIns;
866  klut_network_node lut_node(
867  s, static_cast<long long>(ntk_topo.constant_value(ntk_topo.get_node(s)) ^ ntk_topo.is_complemented(s)),
868  fanIns, true, i, true);
869  luts.push_back(lut_node);
870  }
871  else if(ntk_topo.is_pi(ntk_topo.get_node(s)))
872  {
873  std::vector<uint64_t> fanIns;
874  fanIns.push_back(s);
875  klut_network_node lut_node(s, static_cast<long long>(ntk_topo.is_complemented(s) ? 1 : 2), fanIns, true, i,
876  false);
877  luts.push_back(lut_node);
878  }
879  }
880  });
881 }
882 
883 template <class kne>
884 static mockturtle::klut_network SimplifyLutNetwork(const kne& klut_e, size_t max_lut_size)
885 {
887 #if MIG_SYNTHESIS
888  mockturtle::shannon_resynthesis<mockturtle::mig_network> fallback;
889  mockturtle::dsd_resynthesis<mockturtle::mig_network, decltype(fallback)> mig_resyn(fallback);
890  auto mig0 = mockturtle::node_resynthesis<mockturtle::mig_network>(klut_e, mig_resyn);
891  auto resyn2 = [&](mockturtle::mig_network& mig) -> mockturtle::mig_network {
892  mockturtle::depth_view mig_depth{mig};
893 
894  mockturtle::mig_algebraic_depth_rewriting_params pm;
895  // pm.strategy = mockturtle::mig_algebraic_depth_rewriting_params::selective;
896 
897  // std::cout << "1st round depth optimization " << std::endl;
898 
899  mockturtle::mig_algebraic_depth_rewriting(mig_depth, pm);
900 
901  mig = mockturtle::cleanup_dangling(mig);
902 
903  // std::cout << "1st round area recovering " << std::endl;
904 
905  // AREA RECOVERING
906  mockturtle::mig_npn_resynthesis resyn;
907  mockturtle::cut_rewriting_params ps;
908 
909  ps.cut_enumeration_ps.cut_size = 4;
910 
911  mockturtle::cut_rewriting(mig, resyn, ps);
912  mig = mockturtle::cleanup_dangling(mig);
913 
914  // std::cout << "2nd round area recovering " << std::endl;
915 
916  // AREA RECOVERING
917  mockturtle::cut_rewriting(mig, resyn, ps);
918  mig = mockturtle::cleanup_dangling(mig);
919 
920  // std::cout << "2nd round depth optimization" << std::endl;
921 
922  // DEPTH REWRITING
923  mockturtle::depth_view mig_depth1{mig};
924 
925  mockturtle::mig_algebraic_depth_rewriting(mig_depth1, pm);
926  mig = mockturtle::cleanup_dangling(mig);
927 
928  // std::cout << "3rd round area recovering" << std::endl;
929 
930  // AREA RECOVERING
931  mockturtle::cut_rewriting(mig, resyn, ps);
932  mig = mockturtle::cleanup_dangling(mig);
933 
934  // std::cout << "4th round area recovering" << std::endl;
935 
936  // AREA RECOVERING
937  mockturtle::cut_rewriting(mig, resyn, ps);
938  mig = mockturtle::cleanup_dangling(mig);
939 
940  // std::cout << "3rd round depth optimization" << std::endl;
941 
942  // DEPTH REWRITING
943  mockturtle::depth_view mig_depth2{mig};
944 
945  mockturtle::mig_algebraic_depth_rewriting(mig_depth2, pm);
946  mig = mockturtle::cleanup_dangling(mig);
947 
948  // std::cout << "5th round area recovering" << std::endl;
949 
950  // AREA RECOVERING
951  mockturtle::cut_rewriting(mig, resyn, ps);
952  mig = mockturtle::cleanup_dangling(mig);
953 
954  // std::cout << "6th round area recovering" << std::endl;
955 
956  // AREA RECOVERING
957  mockturtle::cut_rewriting(mig, resyn, ps);
958  mig = mockturtle::cleanup_dangling(mig);
959 
960  // std::cout << "Final depth optimization" << std::endl;
961 
962  // DEPTH REWRITING
963  mockturtle::depth_view mig_depth3{mig};
964 
965  // std::cout << "Network Optimized" << std::endl;
966 
967  mockturtle::mig_algebraic_depth_rewriting(mig_depth3, pm);
968  mig = mockturtle::cleanup_dangling(mig);
969 
970  // std::cout << "Majority nodes " << mig.num_gates() << " MIG depth " << mig_depth3.depth() << std::endl;
971 
972  return mig;
973  };
974  resyn2(mig0);
975  auto cleanedUp = mockturtle::cleanup_dangling(mig0);
976 
977  mockturtle::mapping_view<mockturtle::mig_network, true> mapped_klut{cleanedUp};
978  std::cerr << "std\n";
979  mockturtle::write_bench(mapped_klut, std::cout);
980  std::cerr << "===============\n";
981 
982  mockturtle::lut_mapping_params mp;
983  mp.cut_enumeration_ps.cut_size = static_cast<uint32_t>(max_lut_size);
984  mp.cut_enumeration_ps.cut_limit = 16;
985 
986 #ifndef NDEBUG
987  mp.verbose = false;
988  mp.cut_enumeration_ps.very_verbose = false;
989 #endif
990 
991  mockturtle::lut_mapping<decltype(mapped_klut), true>(mapped_klut, mp);
992  std::cerr << "lut\n";
993  std::cerr << "===============\n";
994  mockturtle::write_bench(mapped_klut, std::cout);
995 
996  auto collapsed = *mockturtle::collapse_mapped_network<mockturtle::klut_network>(mapped_klut);
997  collapsed = mockturtle::cleanup_luts(collapsed);
998  std::cerr << "res\n";
999  mockturtle::write_bench(collapsed, std::cout);
1000  std::cerr << "===============\n";
1001 
1002 #else
1003  mockturtle::shannon_resynthesis<mockturtle::aig_network> fallback;
1004  mockturtle::dsd_resynthesis<mockturtle::aig_network, decltype(fallback)> aig_resyn(fallback);
1005  auto aig = mockturtle::node_resynthesis<mockturtle::aig_network>(klut_e, aig_resyn);
1006 
1007 #if 0
1008  auto resyn2 = [&](mockturtle::aig_network& aig) -> mockturtle::aig_network {
1009  mockturtle::xag_npn_resynthesis<mockturtle::aig_network> resyn;
1010  mockturtle::cut_rewriting_params ps;
1011  ps.cut_enumeration_ps.cut_size = 4;
1012 
1013  mockturtle::cut_rewriting(aig, resyn, ps);
1014  aig = mockturtle::cleanup_dangling(aig);
1015  mockturtle::cut_rewriting(aig, resyn, ps);
1016  aig = mockturtle::cleanup_dangling(aig);
1017 
1018  mockturtle::cut_rewriting(aig, resyn, ps);
1019  aig = mockturtle::cleanup_dangling(aig);
1020 
1021  mockturtle::cut_rewriting(aig, resyn, ps);
1022  aig = mockturtle::cleanup_dangling(aig);
1023 
1024  mockturtle::cut_rewriting(aig, resyn, ps);
1025  aig = mockturtle::cleanup_dangling(aig);
1026 
1027  mockturtle::cut_rewriting(aig, resyn, ps);
1028  aig = mockturtle::cleanup_dangling(aig);
1029 
1030  mockturtle::cut_rewriting(aig, resyn, ps);
1031  aig = mockturtle::cleanup_dangling(aig);
1032 
1033  mockturtle::cut_rewriting(aig, resyn, ps);
1034  aig = mockturtle::cleanup_dangling(aig);
1035 
1036  mockturtle::cut_rewriting(aig, resyn, ps);
1037  aig = mockturtle::cleanup_dangling(aig);
1038 
1039  mockturtle::cut_rewriting(aig, resyn, ps);
1040  aig = mockturtle::cleanup_dangling(aig);
1041 
1042  return aig;
1043  };
1044 
1045  auto resyn2_v2 = [&](mockturtle::aig_network& aig) -> mockturtle::aig_network {
1046  mockturtle::xag_npn_resynthesis<mockturtle::aig_network> resyn;
1047  mockturtle::bidecomposition_resynthesis<mockturtle::aig_network> fallback;
1048  mockturtle::dsd_resynthesis<mockturtle::aig_network, decltype( fallback )> rf_resyn( fallback );
1049  mockturtle::cut_rewriting_params ps;
1050  mockturtle::refactoring_params rp;
1051 
1052  ps.cut_enumeration_ps.cut_size = 4;
1053  rp.allow_zero_gain = false;
1054 
1055  aig= mockturtle::balancing(aig, {mockturtle::sop_rebalancing<mockturtle::aig_network>{}});
1056  aig = mockturtle::cleanup_dangling(aig);
1057 
1058  mockturtle::cut_rewriting(aig, resyn, ps);
1059  aig = mockturtle::cleanup_dangling(aig);
1060 
1061  mockturtle::refactoring(aig, rf_resyn, rp);
1062  aig = mockturtle::cleanup_dangling(aig);
1063 
1064  aig= mockturtle::balancing(aig, {mockturtle::sop_rebalancing<mockturtle::aig_network>{}});
1065  aig = mockturtle::cleanup_dangling(aig);
1066 
1067  mockturtle::cut_rewriting(aig, resyn, ps);
1068  aig = mockturtle::cleanup_dangling(aig);
1069 
1070  ps.allow_zero_gain = true;
1071  mockturtle::cut_rewriting(aig, resyn, ps);
1072  aig = mockturtle::cleanup_dangling(aig);
1073 
1074  aig= mockturtle::balancing(aig, {mockturtle::sop_rebalancing<mockturtle::aig_network>{}});
1075  aig = mockturtle::cleanup_dangling(aig);
1076 
1077  rp.allow_zero_gain = true;
1078  mockturtle::refactoring(aig, rf_resyn, rp);
1079  aig = mockturtle::cleanup_dangling(aig);
1080 
1081  mockturtle::cut_rewriting(aig, resyn, ps);
1082  aig = mockturtle::cleanup_dangling(aig);
1083 
1084  aig= mockturtle::balancing(aig, {mockturtle::sop_rebalancing<mockturtle::aig_network>{}});
1085  aig = mockturtle::cleanup_dangling(aig);
1086 
1087  return aig;
1088  };
1089 
1090  auto cleanedUp = resyn2(aig);
1091 #else
1092  auto cleanedUp = cleanup_dangling(aig);
1093 #endif
1094  mockturtle::mapping_view<mockturtle::aig_network, true> mapped_klut{cleanedUp};
1095  // std::cerr << "std\n";
1096  // mockturtle::write_bench(mapped_klut, std::cout);
1097  // std::cerr << "===============\n";
1098 
1099  mockturtle::lut_mapping_params mp;
1100  mp.cut_enumeration_ps.cut_size = static_cast<uint32_t>(max_lut_size);
1101  mp.cut_enumeration_ps.cut_limit = 16;
1102 
1103 #ifndef NDEBUG
1104  mp.verbose = false;
1105  mp.cut_enumeration_ps.very_verbose = false;
1106 #endif
1107 
1108  mockturtle::lut_mapping<decltype(mapped_klut), true>(mapped_klut, mp);
1109  // std::cerr << "lut\n";
1110  // std::cerr << "===============\n";
1111  // mockturtle::write_bench(mapped_klut, std::cout);
1112 
1113 #if USE_SAT
1114  mockturtle::satlut_mapping_params satlut_mp;
1115  satlut_mp.cut_enumeration_ps.cut_size = max_lut_size;
1116  satlut_mp.cut_enumeration_ps.cut_limit = 16;
1117  satlut_mp.conflict_limit = 100;
1118  satlut_mp.progress = true;
1119  mockturtle::satlut_mapping_stats st;
1120 
1121  mockturtle::satlut_mapping<decltype(mapped_klut), true>(mapped_klut, 32, satlut_mp, &st);
1122  std::cerr << "sat\n";
1123  std::cerr << "===============\n";
1124  mockturtle::write_bench(mapped_klut, std::cout);
1125 #endif
1126  auto collapsed = *mockturtle::collapse_mapped_network<mockturtle::klut_network>(mapped_klut);
1127  collapsed = mockturtle::cleanup_luts(collapsed);
1128 // std::cerr << "res\n";
1129 // mockturtle::write_bench(collapsed, std::cout);
1130 // std::cerr << "===============\n";
1131 #endif
1132  return collapsed;
1133 }
1134 
1135 bool lut_transformation::ProcessBasicBlock(std::pair<unsigned int, blocRef> block)
1136 {
1137  klut_network_ext klut_e;
1138  auto BB_index = block.first;
1139 
1140  std::map<unsigned int, mockturtle::klut_network::signal> nodeRefToSignal;
1141  std::map<unsigned int, std::vector<mockturtle::klut_network::signal>> nodeRefToSignalBus;
1142 
1143  std::vector<tree_nodeRef> pis;
1144  std::vector<int> pis_offset;
1145  std::vector<tree_nodeRef> pos;
1146  std::vector<unsigned> pos_offset;
1147 
1148  auto DefaultUnsignedLongLongInt = this->tree_man->GetUnsignedLongLongType();
1149 
1153  pis.push_back(TM->CreateUniqueIntegerCst(0, DefaultUnsignedLongLongInt));
1154  pis_offset.push_back(0);
1155 
1159  pis.push_back(TM->CreateUniqueIntegerCst(1, DefaultUnsignedLongLongInt));
1160  pis_offset.push_back(0);
1161 
1162  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing BB" + STR(BB_index));
1163  const auto& statements = block.second->CGetStmtList();
1164 
1166  bool modified = false;
1167 
1168  for(const auto& statement : statements)
1169  {
1170  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing " + statement->ToString());
1171 
1172  if(!AppM->ApplyNewTransformation())
1173  {
1174  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Reached max cfg transformations");
1175  continue;
1176  }
1177 
1178  if(GET_NODE(statement)->get_kind() != gimple_assign_K)
1179  {
1180  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not a gimple assign");
1181  continue;
1182  }
1183 
1184  auto* gimpleAssign = GetPointer<gimple_assign>(GET_NODE(statement));
1185  enum kind code1 = GET_NODE(gimpleAssign->op1)->get_kind();
1187  "---Analyzing code " + GET_NODE(gimpleAssign->op1)->get_kind_text());
1188 
1189  if(code1 == lut_expr_K)
1190  {
1191  auto* le = GetPointer<lut_expr>(GET_NODE(gimpleAssign->op1));
1192 
1193  std::vector<mockturtle::klut_network::signal> ops;
1194  for(auto op : {le->op1, le->op2, le->op3, le->op4, le->op5, le->op6, le->op7, le->op8})
1195  {
1196  if(!op)
1197  {
1198  break;
1199  }
1200 
1201  // if the first operand has already been processed then the previous signal is used
1202  if(nodeRefToSignal.find(GET_INDEX_NODE(op)) != nodeRefToSignal.end())
1203  {
1205  ops.push_back(nodeRefToSignal[GET_INDEX_NODE(op)]);
1206  }
1207  else
1208  { // otherwise the operand is a primary input
1209  mockturtle::klut_network::signal kop = 0;
1210 
1211  if(GET_NODE(op)->get_kind() == integer_cst_K)
1212  {
1213  const auto cst_val = tree_helper::GetConstValue(op);
1214  kop = cst_val == 0 ? klut_e.get_constant(false) : klut_e.create_not(klut_e.get_constant(false));
1215  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, cst_val == 0 ? "---used gnd" : "---used vdd");
1216  modified = true;
1217  }
1218  else if(CheckIfPI(op, BB_index))
1219  {
1221  kop = klut_e.create_pi();
1222  pis.push_back(op);
1223  pis_offset.push_back(0);
1224  }
1225  else
1226  {
1227  THROW_ERROR("unexpected condition: " + GET_NODE(op)->ToString());
1228  }
1229 
1230  nodeRefToSignal[GET_INDEX_NODE(op)] = kop;
1231  ops.push_back(kop);
1232  }
1233  }
1234 
1236  "---translating in klut " + STR(tree_helper::GetConstValue(le->op0)));
1237  const auto cst_val = tree_helper::GetConstValue(le->op0);
1239  "Cast will change signedness of current value: " + STR(cst_val));
1240  auto res = klut_e.create_lut(ops, static_cast<long long>(cst_val));
1241  nodeRefToSignal[GET_INDEX_NODE(gimpleAssign->op0)] = res;
1242 
1243  if(this->CheckIfPO(gimpleAssign))
1244  {
1246  klut_e.create_po(res);
1247  pos.push_back(statement);
1248  pos_offset.push_back(0);
1249  }
1250 
1251  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1252  // mockturtle::write_bench(klut_e, std::cout);
1253  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1255  continue;
1256  }
1257 
1258  if(code1 == truth_not_expr_K || code1 == bit_not_expr_K)
1259  {
1260  auto* ne = GetPointer<unary_expr>(GET_NODE(gimpleAssign->op1));
1261  auto is_size_one = CHECK_NOT_EXPR_SIZE(ne);
1262  if(!is_size_one)
1263  {
1264  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not a Boolean not expr");
1265  continue;
1266  }
1267  std::vector<mockturtle::klut_network::signal> ops;
1268  for(auto op : {ne->op})
1269  {
1270  // if the first operand has already been processed then the previous signal is used
1271  if(nodeRefToSignal.find(GET_INDEX_NODE(op)) != nodeRefToSignal.end())
1272  {
1274  ops.push_back(nodeRefToSignal[GET_INDEX_NODE(op)]);
1275  }
1276  else
1277  { // otherwise the operand is a primary input
1278  mockturtle::klut_network::signal kop = 0;
1279 
1280  if(GET_NODE(op)->get_kind() == integer_cst_K)
1281  {
1282  const auto cst_val = tree_helper::GetConstValue(op);
1283  kop = cst_val == 0 ? klut_e.get_constant(false) : klut_e.create_not(klut_e.get_constant(false));
1284  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, cst_val == 0 ? "---used gnd" : "---used vdd");
1285  }
1286  else if(CheckIfPI(op, BB_index))
1287  {
1289  kop = klut_e.create_pi();
1290  pis.push_back(op);
1291  pis_offset.push_back(0);
1292  }
1293  else
1294  {
1295  THROW_ERROR("unexpected condition");
1296  }
1297 
1298  nodeRefToSignal[GET_INDEX_NODE(op)] = kop;
1299  ops.push_back(kop);
1300  }
1301  }
1302 
1303  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---translating in klut");
1304  auto res = klut_e.create_not(ops.at(0));
1305  nodeRefToSignal[GET_INDEX_NODE(gimpleAssign->op0)] = res;
1306 
1307  if(this->CheckIfPO(gimpleAssign))
1308  {
1310  klut_e.create_po(res);
1311  pos.push_back(statement);
1312  pos_offset.push_back(0);
1313  }
1314 
1315  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1316  // mockturtle::write_bench(klut_e, std::cout);
1317  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1318  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--truth_not_expr/bit_not_expr found");
1319 
1320  modified = true;
1321  continue;
1322  }
1323 
1324  if(code1 == cond_expr_K)
1325  {
1326  auto* ce = GetPointer<cond_expr>(GET_NODE(gimpleAssign->op1));
1327  auto is_size_one = CHECK_COND_EXPR_SIZE(ce);
1328  if(!is_size_one)
1329  {
1330  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not a Boolean cond_expr");
1331  continue;
1332  }
1333  std::vector<mockturtle::klut_network::signal> ops;
1334  for(auto op : {ce->op0, ce->op1, ce->op2})
1335  {
1336  // if the first operand has already been processed then the previous signal is used
1337  if(nodeRefToSignal.find(GET_INDEX_NODE(op)) != nodeRefToSignal.end())
1338  {
1340  ops.push_back(nodeRefToSignal[GET_INDEX_NODE(op)]);
1341  }
1342  else
1343  { // otherwise the operand is a primary input
1344  mockturtle::klut_network::signal kop = 0;
1345 
1346  if(GET_NODE(op)->get_kind() == integer_cst_K)
1347  {
1348  const auto cst_val = tree_helper::GetConstValue(op);
1349  kop = cst_val == 0 ? klut_e.get_constant(false) : klut_e.create_not(klut_e.get_constant(false));
1350  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, cst_val == 0 ? "---used gnd" : "---used vdd");
1351  }
1352  else if(CheckIfPI(op, BB_index))
1353  {
1355  kop = klut_e.create_pi();
1356  pis.push_back(op);
1357  pis_offset.push_back(0);
1358  }
1359  else
1360  {
1361  THROW_ERROR("unexpected condition: " + GET_NODE(op)->ToString());
1362  }
1363 
1364  nodeRefToSignal[GET_INDEX_NODE(op)] = kop;
1365  ops.push_back(kop);
1366  }
1367  }
1368 
1369  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---translating in klut");
1370  auto res = klut_e.create_ite(ops.at(0), ops.at(1), ops.at(2));
1371  nodeRefToSignal[GET_INDEX_NODE(gimpleAssign->op0)] = res;
1372 
1373  if(this->CheckIfPO(gimpleAssign))
1374  {
1376  klut_e.create_po(res);
1377  pos.push_back(statement);
1378  pos_offset.push_back(0);
1379  }
1380 
1381  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1382  // mockturtle::write_bench(klut_e, std::cout);
1383  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1384  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--cond_expr found");
1385 
1386  modified = true;
1387  continue;
1388  }
1389 
1390  auto* binaryExpression = GetPointer<binary_expr>(GET_NODE(gimpleAssign->op1));
1391  if(!binaryExpression)
1392  {
1393  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not a binary expression");
1394  continue;
1395  }
1396 
1398  {
1399  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Boolean operands");
1400 
1401  klut_network_fn nodeCreateFn = GetBooleanNodeCreationFunction(code1);
1402 
1403  if(nodeCreateFn == nullptr)
1404  {
1405  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not supported expression");
1406  continue;
1407  }
1408 
1409  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---translating in klut");
1410 
1411  mockturtle::klut_network::signal res;
1412  mockturtle::klut_network::signal op1 = 0;
1413  mockturtle::klut_network::signal op2 = 0;
1414 
1415  // if the first operand has already been processed then the previous signal is used
1416  if(nodeRefToSignal.find(GET_INDEX_NODE(binaryExpression->op0)) != nodeRefToSignal.end())
1417  {
1419  "---used PI " + GET_NODE(binaryExpression->op0)->ToString());
1420  op1 = nodeRefToSignal[GET_INDEX_NODE(binaryExpression->op0)];
1421  }
1422  else
1423  { // otherwise the operand is a primary input
1424  if(GET_NODE(binaryExpression->op0)->get_kind() == integer_cst_K)
1425  {
1426  const auto cst_val = tree_helper::GetConstValue(binaryExpression->op0);
1427  op1 = cst_val == 0 ? klut_e.get_constant(false) : klut_e.create_not(klut_e.get_constant(false));
1428  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, (cst_val == 0) ? "---used gnd" : "---used vdd");
1429  }
1430  else if(CheckIfPI(binaryExpression->op0, BB_index))
1431  {
1433  "---used PI " + GET_NODE(binaryExpression->op0)->ToString());
1434  op1 = klut_e.create_pi();
1435  pis.push_back(binaryExpression->op0);
1436  pis_offset.push_back(0);
1437  nodeRefToSignal[GET_INDEX_NODE(binaryExpression->op0)] = op1;
1438  }
1439  else
1440  {
1441  THROW_ERROR("unexpected condition");
1442  }
1443  }
1444 
1445  // if the second operand has already been processed then the previous signal is used
1446  if(nodeRefToSignal.find(GET_INDEX_NODE(binaryExpression->op1)) != nodeRefToSignal.end())
1447  {
1449  "---used PI " + GET_NODE(binaryExpression->op1)->ToString());
1450  op2 = nodeRefToSignal[GET_INDEX_NODE(binaryExpression->op1)];
1451  }
1452  else
1453  { // otherwise the operand is a primary input
1454  if(GET_NODE(binaryExpression->op1)->get_kind() == integer_cst_K)
1455  {
1456  const auto cst_val = tree_helper::GetConstValue(binaryExpression->op1);
1457  op2 = cst_val == 0 ? klut_e.get_constant(false) : klut_e.create_not(klut_e.get_constant(false));
1458  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, (cst_val == 0) ? "---used gnd" : "---used vdd");
1459  }
1460  else if(CheckIfPI(binaryExpression->op1, BB_index))
1461  {
1463  "---used PI " + GET_NODE(binaryExpression->op1)->ToString());
1464  op2 = klut_e.create_pi();
1465  pis.push_back(binaryExpression->op1);
1466  pis_offset.push_back(0);
1467  nodeRefToSignal[GET_INDEX_NODE(binaryExpression->op1)] = op2;
1468  }
1469  else
1470  {
1471  THROW_ERROR("unexpected condition");
1472  }
1473  }
1474 
1475  res = (klut_e.*nodeCreateFn)(op1, op2);
1476  nodeRefToSignal[GET_INDEX_NODE(gimpleAssign->op0)] = res;
1477 
1478  if(this->CheckIfPO(gimpleAssign))
1479  {
1481  klut_e.create_po(res);
1482  pos.push_back(statement);
1483  pos_offset.push_back(0);
1484  }
1485 
1486  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1487  // mockturtle::write_bench(klut_e, std::cout);
1488  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1489  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed statement ");
1490  modified = true;
1491  continue;
1492  }
1494  CHECK_BIN_EXPR_INT_SIZE(binaryExpression, parameters->GetParameter<unsigned int>("MAX_LUT_INT_SIZE")))
1495  {
1496  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Integer operands");
1497 
1498  klut_network_fn_v nodeCreateFn = GetIntegerNodeCreationFunction(code1);
1499 
1500  if(nodeCreateFn == nullptr)
1501  {
1502  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Not supported expression");
1503  continue;
1504  }
1505 
1506  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---translating in klut");
1507 
1508  std::vector<mockturtle::klut_network::signal> res;
1509  std::vector<mockturtle::klut_network::signal> op1 = {};
1510  std::vector<mockturtle::klut_network::signal> op2 = {};
1511 
1512  // if the first operand has already been processed then the previous signal is used
1513  if(nodeRefToSignalBus.find(GET_INDEX_NODE(binaryExpression->op0)) != nodeRefToSignalBus.end())
1514  {
1516  "---used PI " + GET_NODE(binaryExpression->op0)->ToString());
1517  op1 = nodeRefToSignalBus[GET_INDEX_NODE(binaryExpression->op0)];
1518  }
1519  else
1520  { // otherwise the operand is a primary input
1521  if(GET_NODE(binaryExpression->op0)->get_kind() == integer_cst_K)
1522  {
1523  const auto cst_val = tree_helper::GetConstValue(binaryExpression->op0);
1524  auto bits = IntegerToBitArray(cst_val, tree_helper::Size(binaryExpression->op0));
1525 
1526  op1 = klut_e.get_constant_v(bits);
1528  }
1529  else if(CheckIfPI(binaryExpression->op0, BB_index))
1530  {
1532  "---used PIs " + GET_NODE(binaryExpression->op0)->ToString());
1533  op1 = klut_e.create_pi_v(tree_helper::Size(binaryExpression->op0));
1534 
1535  int index = 0;
1536  std::for_each(op1.begin(), op1.end(), [&binaryExpression, &pis, &pis_offset, &index](auto /*op*/) {
1537  pis.push_back(binaryExpression->op0);
1538  pis_offset.push_back(index);
1539  ++index;
1540  });
1541 
1542  nodeRefToSignalBus[GET_INDEX_NODE(binaryExpression->op0)] = op1;
1543  }
1544  else
1545  {
1546  THROW_ERROR("unexpected condition");
1547  }
1548  }
1549 
1550  // if the second operand has already been processed then the previous signal is used
1551  if(nodeRefToSignalBus.find(GET_INDEX_NODE(binaryExpression->op1)) != nodeRefToSignalBus.end())
1552  {
1554  "---used PI " + GET_NODE(binaryExpression->op1)->ToString());
1555  op2 = nodeRefToSignalBus[GET_INDEX_NODE(binaryExpression->op1)];
1556  }
1557  else
1558  { // otherwise the operand is a primary input
1559  if(GET_NODE(binaryExpression->op1)->get_kind() == integer_cst_K)
1560  {
1561  const auto cst_val = tree_helper::GetConstValue(binaryExpression->op1);
1562  auto bits = IntegerToBitArray(cst_val, tree_helper::Size(binaryExpression->op1));
1563 
1564  op2 = klut_e.get_constant_v(bits);
1566  }
1567  else if(CheckIfPI(binaryExpression->op1, BB_index))
1568  {
1570  "---used PIs " + GET_NODE(binaryExpression->op1)->ToString());
1571  op2 = klut_e.create_pi_v(tree_helper::Size(binaryExpression->op1));
1572 
1573  int index = 0;
1574  std::for_each(op2.begin(), op2.end(), [&binaryExpression, &pis, &pis_offset, &index](auto /*op*/) {
1575  pis.push_back(binaryExpression->op1);
1576  pis_offset.push_back(index);
1577  ++index;
1578  });
1579 
1580  nodeRefToSignalBus[GET_INDEX_NODE(binaryExpression->op1)] = op2;
1581  }
1582  else
1583  {
1584  THROW_ERROR("unexpected condition");
1585  }
1586  }
1587  bool isSigned = tree_helper::is_int(TM, GET_INDEX_NODE(binaryExpression->op0));
1588  res = (klut_e.*nodeCreateFn)(op1, op2, isSigned);
1589  nodeRefToSignalBus[GET_INDEX_NODE(gimpleAssign->op0)] = res;
1590  if(res.size() == 1)
1591  {
1592  nodeRefToSignal[GET_INDEX_NODE(gimpleAssign->op0)] = res.at(0);
1593  }
1594  if(this->CheckIfPO(gimpleAssign))
1595  {
1597  klut_e.create_po_v(res);
1598 
1599  unsigned int index = 0;
1600  std::for_each(res.begin(), res.end(), [&statement, &pos, &pos_offset, &index](auto /*op*/) {
1601  pos.push_back(statement);
1602  pos_offset.push_back(index);
1603  ++index;
1604  });
1605  }
1606 
1607  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1608  // mockturtle::write_bench(klut_e, std::cout);
1609  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1610  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed statement ");
1611  modified = true;
1612  continue;
1613  }
1614  else
1615  {
1616  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Integer operands' size is too large");
1617  continue;
1618  }
1619  }
1620 
1621  if(modified)
1622  {
1623  // mockturtle::write_bench(klut_e, std::cout);
1624  // INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---====");
1625  mockturtle::klut_network klut = SimplifyLutNetwork(klut_e, this->max_lut_size);
1626  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---PI size " + STR(pis.size()));
1627 #ifndef NDEBUG
1629  mockturtle::write_bench(klut, std::cout);
1630 #endif
1631 
1632  std::vector<klut_network_node> luts;
1633  ParseKLutNetwork(klut, luts);
1634 
1635  std::map<mockturtle::klut_network::node, tree_nodeRef> internal_nets;
1636  std::vector<tree_nodeRef> prev_stmts_to_add;
1637  for(auto lut : luts)
1638  {
1639  if(!AppM->ApplyNewTransformation())
1640  {
1641  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Reached max cfg transformations");
1642  continue;
1643  }
1644 
1645  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---index: " + STR(lut.index));
1646  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "--- po_index: " + STR(lut.po_index));
1647  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "--- func: " + STR(lut.lut_constant));
1648 #ifndef NDEBUG
1649  for(auto in : lut.fan_in)
1651 #endif
1652  if(lut.is_po)
1653  {
1655  auto po_stmpt = pos.at(lut.po_index);
1657  for(auto stmt : prev_stmts_to_add)
1658  {
1660  "---Adding statement " + GET_NODE(stmt)->ToString());
1661  block.second->PushBefore(stmt, po_stmpt, AppM);
1662  }
1663  prev_stmts_to_add.clear();
1664  }
1665  tree_nodeRef lut_constant_node = TM->CreateUniqueIntegerCst(lut.lut_constant, DefaultUnsignedLongLongInt);
1666  tree_nodeRef op1, op2, op3, op4, op5, op6, op7, op8;
1667  auto p_index = 1u;
1668  for(auto in : lut.fan_in)
1669  {
1670  tree_nodeRef operand;
1671  if(klut.is_pi(in))
1672  {
1673  operand = pis.at(in);
1674  auto operand_offset = pis_offset.at(in);
1675 
1676  if(tree_helper::Size(operand) == 1 && !tree_helper::IsBooleanType(operand))
1677  {
1678  THROW_ASSERT(operand_offset == 0, "unexpected condition");
1679  operand = CreateBitSelectionNodeOrCast(operand, 0, prev_stmts_to_add);
1680  }
1681  else if(tree_helper::Size(operand) > 1)
1682  {
1683  operand = CreateBitSelectionNodeOrCast(operand, operand_offset, prev_stmts_to_add);
1684  }
1685  }
1686  else if(internal_nets.find(in) != internal_nets.end())
1687  {
1688  operand = internal_nets.find(in)->second;
1689  }
1690  else
1691  {
1692  THROW_ERROR("unexpected condition" + STR(p_index));
1693  }
1694 
1695  if(p_index == 1)
1696  {
1697  op1 = operand;
1698  }
1699  else if(p_index == 2)
1700  {
1701  op2 = operand;
1702  }
1703  else if(p_index == 3)
1704  {
1705  op3 = operand;
1706  }
1707  else if(p_index == 4)
1708  {
1709  op4 = operand;
1710  }
1711  else if(p_index == 5)
1712  {
1713  op5 = operand;
1714  }
1715  else if(p_index == 6)
1716  {
1717  op6 = operand;
1718  }
1719  else if(p_index == 7)
1720  {
1721  op7 = operand;
1722  }
1723  else if(p_index == 8)
1724  {
1725  op8 = operand;
1726  }
1727  else
1728  {
1729  THROW_ERROR("unexpected number of inputs");
1730  }
1731  ++p_index;
1732  }
1733 
1734  if(lut.is_po)
1735  {
1736  auto po_stmpt = pos.at(lut.po_index);
1737  // auto po_offset = pos_offset.at(lut.po_index);
1739  for(auto stmt : prev_stmts_to_add)
1740  {
1742  "---Adding statement " + GET_NODE(stmt)->ToString());
1743  block.second->PushBefore(stmt, po_stmpt, AppM);
1744  }
1745  prev_stmts_to_add.clear();
1747  "---Before statement " + GET_NODE(po_stmpt)->ToString());
1748  auto* gimpleAssign = GetPointer<gimple_assign>(GET_NODE(po_stmpt));
1749  THROW_ASSERT(gimpleAssign, "unexpected condition");
1750  const std::string srcp_default = gimpleAssign->include_name + ":" + STR(gimpleAssign->line_number) + ":" +
1751  STR(gimpleAssign->column_number);
1752  auto ga_op0 = GET_NODE(gimpleAssign->op0);
1753  auto* ssa_ga_op0 = GetPointer<ssa_name>(ga_op0);
1754  THROW_ASSERT(ssa_ga_op0, "unexpected condition");
1755  if(!lut.is_constant)
1756  {
1757  internal_nets[lut.index] = gimpleAssign->op0;
1758  }
1759 
1760  if(lut.is_constant)
1761  {
1762  const auto new_op1 = TM->CreateUniqueIntegerCst(lut.lut_constant, ssa_ga_op0->type);
1763  TM->ReplaceTreeNode(po_stmpt, gimpleAssign->op1, new_op1);
1764  }
1765  else if(lut.fan_in.size() == 1 && lut.lut_constant == 2)
1766  {
1767  const auto op1_type_node = tree_helper::CGetType(op1);
1768  if(GET_INDEX_NODE(ssa_ga_op0->type) == op1_type_node->index)
1769  {
1771  "---Replacing " + STR(gimpleAssign->op1) + " with " + STR(op1));
1772  TM->ReplaceTreeNode(po_stmpt, gimpleAssign->op1, op1);
1773  }
1774  else
1775  {
1776  const auto new_op1 =
1777  tree_man->create_unary_operation(ssa_ga_op0->type, op1, srcp_default, nop_expr_K);
1779  "---Replacing " + STR(gimpleAssign->op1) + " with " + STR(new_op1));
1780  TM->ReplaceTreeNode(po_stmpt, gimpleAssign->op1, new_op1);
1781  }
1782  }
1783  else
1784  {
1785  auto boolType = tree_man->GetBooleanType();
1787  auto check_lut_compatibility = [&](tree_nodeRef& lut_operand) {
1788  if(lut_operand && !tree_helper::IsBooleanType(lut_operand))
1789  {
1790  tree_nodeRef ga_nop =
1791  tree_man->CreateNopExpr(lut_operand, boolType, tree_nodeRef(), tree_nodeRef(), function_id);
1792  block.second->PushBefore(ga_nop, po_stmpt, AppM);
1793  lut_operand = GetPointer<gimple_assign>(GET_NODE(ga_nop))->op0;
1794  }
1795  };
1796  check_lut_compatibility(op1);
1797  check_lut_compatibility(op2);
1798  check_lut_compatibility(op3);
1799  check_lut_compatibility(op4);
1800  check_lut_compatibility(op5);
1801  check_lut_compatibility(op6);
1802  check_lut_compatibility(op7);
1803  check_lut_compatibility(op8);
1804  if(tree_helper::IsBooleanType(gimpleAssign->op0))
1805  {
1806  tree_nodeRef new_op1 = tree_man->create_lut_expr(ssa_ga_op0->type, lut_constant_node, op1, op2, op3,
1807  op4, op5, op6, op7, op8, srcp_default);
1809  "---Replacing " + STR(gimpleAssign->op1) + " with " + STR(op1));
1810  TM->ReplaceTreeNode(po_stmpt, gimpleAssign->op1, new_op1);
1811  }
1812  else
1813  {
1814  tree_nodeRef lut_node = tree_man->create_lut_expr(boolType, lut_constant_node, op1, op2, op3, op4,
1815  op5, op6, op7, op8, srcp_default);
1816  auto lut_ga = tree_man->CreateGimpleAssign(boolType, TM->CreateUniqueIntegerCst(0, boolType),
1817  TM->CreateUniqueIntegerCst(1, boolType), lut_node,
1818  function_id, srcp_default);
1820  "---Adding statement " + GET_NODE(lut_ga)->ToString());
1821  block.second->PushBefore(lut_ga, po_stmpt, AppM);
1822  auto ssa_vd = GetPointer<gimple_assign>(GET_NODE(lut_ga))->op0;
1823  tree_nodeRef new_op1 =
1824  tree_man->create_unary_operation(ssa_ga_op0->type, ssa_vd, srcp_default, nop_expr_K);
1826  "---Replacing " + STR(gimpleAssign->op1) + " with " + STR(op1));
1827  TM->ReplaceTreeNode(po_stmpt, gimpleAssign->op1, new_op1);
1828  }
1829  }
1830  AppM->RegisterTransformation(GetName(), po_stmpt);
1832  "---Modified statement " + GET_NODE(po_stmpt)->ToString());
1833  }
1834  else
1835  {
1836  auto boolType = tree_man->GetBooleanType();
1838  auto check_lut_compatibility = [&](tree_nodeRef& lut_operand) {
1839  if(lut_operand && !tree_helper::IsBooleanType(lut_operand))
1840  {
1841  tree_nodeRef ga_nop =
1842  tree_man->CreateNopExpr(lut_operand, boolType, tree_nodeRef(), tree_nodeRef(), function_id);
1843  prev_stmts_to_add.push_back(ga_nop);
1844  lut_operand = GetPointer<gimple_assign>(GET_NODE(ga_nop))->op0;
1845  }
1846  };
1847  check_lut_compatibility(op1);
1848  check_lut_compatibility(op2);
1849  check_lut_compatibility(op3);
1850  check_lut_compatibility(op4);
1851  check_lut_compatibility(op5);
1852  check_lut_compatibility(op6);
1853  check_lut_compatibility(op7);
1854  check_lut_compatibility(op8);
1855  tree_nodeRef new_op1 = tree_man->create_lut_expr(boolType, lut_constant_node, op1, op2, op3, op4, op5, op6,
1856  op7, op8, BUILTIN_SRCP);
1857  auto lut_ga = tree_man->CreateGimpleAssign(boolType, TM->CreateUniqueIntegerCst(0, boolType),
1858  TM->CreateUniqueIntegerCst(1, boolType), new_op1, function_id,
1859  BUILTIN_SRCP);
1860  auto ssa_vd = GetPointer<gimple_assign>(GET_NODE(lut_ga))->op0;
1861  prev_stmts_to_add.push_back(lut_ga);
1862  internal_nets[lut.index] = ssa_vd;
1863  }
1864  }
1865  THROW_ASSERT(prev_stmts_to_add.empty(), "unexpected condition");
1867 #if HAVE_ASSERTS
1868  auto nStmts = statements.size();
1869 #endif
1870  // for(auto stmt: statements)
1871  // std::cerr<< "Before STMT " << stmt->ToString()<<"\n";
1872  block.second->ReorderLUTs();
1873  // for(auto stmt: statements)
1874  // std::cerr<< "STMT " << stmt->ToString()<<"\n";
1875  THROW_ASSERT(nStmts == statements.size(), "unexpected result");
1876  }
1877 
1878  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed BB" + STR(block.first));
1879 
1880  return modified;
1881 }
1882 
1883 #pragma region Life cycle
1884 
1886  unsigned int _function_id, const DesignFlowManagerConstRef _design_flow_manager)
1887  : FunctionFrontendFlowStep(_AppM, _function_id, LUT_TRANSFORMATION, _design_flow_manager, Param),
1889 {
1890  debug_level = Param->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
1891 }
1892 
1894 
1897 {
1899  switch(relationship_type)
1900  {
1902  {
1903  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
1904  {
1905  relationships.insert(std::make_pair(BITVALUE_RANGE, SAME_FUNCTION));
1906  }
1907  relationships.insert(std::make_pair(CSE_STEP, SAME_FUNCTION));
1908  relationships.insert(std::make_pair(DEAD_CODE_ELIMINATION_IPA, WHOLE_APPLICATION));
1909  break;
1910  }
1912  {
1913  relationships.insert(std::make_pair(DEAD_CODE_ELIMINATION, SAME_FUNCTION));
1914  break;
1915  }
1917  {
1919  {
1920  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
1921  {
1922  relationships.insert(std::make_pair(BIT_VALUE, SAME_FUNCTION));
1923  }
1924  relationships.insert(std::make_pair(DEAD_CODE_ELIMINATION, SAME_FUNCTION));
1925  }
1926  break;
1927  }
1928  default:
1929  THROW_UNREACHABLE("");
1930  }
1931  return relationships;
1932 }
1933 
1935  const DesignFlowStep::RelationshipType relationship_type)
1936 {
1937  switch(relationship_type)
1938  {
1940  break;
1942  {
1943  const auto design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
1944  const auto technology_flow_step_factory = GetPointerS<const TechnologyFlowStepFactory>(
1945  design_flow_manager.lock()->CGetDesignFlowStepFactory("Technology"));
1946  const auto technology_flow_signature =
1948  const auto technology_flow_step = design_flow_manager.lock()->GetDesignFlowStep(technology_flow_signature);
1949  const auto technology_design_flow_step =
1950  technology_flow_step ?
1951  design_flow_graph->CGetDesignFlowStepInfo(technology_flow_step)->design_flow_step :
1952  technology_flow_step_factory->CreateTechnologyFlowStep(TechnologyFlowStep_Type::LOAD_TECHNOLOGY);
1953  relationship.insert(technology_design_flow_step);
1954  break;
1955  }
1957  break;
1958  default:
1959  THROW_UNREACHABLE("");
1960  }
1961 
1962  FunctionFrontendFlowStep::ComputeRelationships(relationship, relationship_type);
1963 }
1964 
1966 {
1967  TM = AppM->get_tree_manager();
1969  THROW_ASSERT(GetPointer<const HLS_manager>(AppM)->get_HLS_device(), "unexpected condition");
1970  const auto hls_d = GetPointerS<const HLS_manager>(AppM)->get_HLS_device();
1971  THROW_ASSERT(hls_d->has_parameter("max_lut_size"), "unexpected condition");
1972  max_lut_size = hls_d->get_parameter<size_t>("max_lut_size");
1973 }
1974 
1976 {
1977  if(max_lut_size == 0 ||
1978  (parameters->IsParameter("lut-transformation") && !parameters->GetParameter<unsigned int>("lut-transformation")))
1979  {
1981  }
1982  const auto fd = GetPointer<const function_decl>(TM->CGetTreeNode(function_id));
1983  THROW_ASSERT(fd && fd->body, "Node is not a function or it has not a body");
1984  const auto sl = GetPointer<const statement_list>(GET_CONST_NODE(fd->body));
1985  THROW_ASSERT(sl, "Body is not a statement list");
1986 
1987  bool modified = false;
1988  for(std::pair<unsigned int, blocRef> block : sl->list_of_bloc)
1989  {
1990  if(this->CheckIfProcessable(block))
1991  {
1992  modified |= this->ProcessBasicBlock(block);
1993  }
1994  }
1995 
1996  if(modified)
1997  {
1998  function_behavior->UpdateBBVersion();
2000  }
2002 }
2003 
2004 #pragma endregion
2005 
2006 #pragma GCC diagnostic pop
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
bool CheckIfProcessable(std::pair< unsigned int, blocRef > block)
Checks if the provided basic block can be further processed.
static bool IsComplexType(const tree_nodeConstRef &type)
Return if treenode is a complex.
lut_transformation(const ParameterConstRef Param, const application_managerRef AppM, unsigned int function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
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;.
bool CheckIfPO(gimple_assign *gimpleAssign)
Checks if the provided gimple_assign is a primary output of lut network.
File containing functions and utilities to support the printing of debug messagges.
static bool is_int(const tree_managerConstRef &TM, const unsigned int index)
Return true if the treenode is of integer type.
Step successfully executed.
TVMArray c1[1]
#define GET_CLASS(obj)
Macro returning the actual type of an object.
void ReplaceTreeNode(const tree_nodeRef &stmt, const tree_nodeRef &old_node, const tree_nodeRef &new_node)
Replace the occurrences of tree node old_node with new_node in statement identified by tn...
Definition of the class representing a generic C application.
refcount< tree_manipulation > tree_manipulationRef
kitty::dynamic_truth_table create_lt_tt(unsigned int bits)
std::string GetName() const override
Return the name of this design step.
static mockturtle::klut_network SimplifyLutNetwork(const kne &klut_e, size_t max_lut_size)
RelationshipType
The relationship type.
Source must be executed to satisfy target.
tree_manipulationRef tree_man
The lut manipulation.
mathematical utility function not provided by standard libraries
TVMArray b0[1]
std::vector< signal > create_eq_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
std::vector< signal > create_pi_v(size_t size)
bool CHECK_BIN_EXPR_INT_SIZE(binary_expr *be, unsigned int max) const
std::vector< signal > get_constant_v(std::vector< bool > bits)
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
std::vector< mockturtle::klut_network::signal >(klut_network_ext::*)(const std::vector< mockturtle::klut_network::signal > &, const std::vector< mockturtle::klut_network::signal > &, bool) klut_network_fn_v
Pointer that points to a function of klut_network_ext, that represents a binary operation between two...
bool is_constant
true in case the node is a constant value
tree_managerRef TM
The tree manager.
const std::vector< enum kind > lutIntegerExpressibleOperations
Collect information about resource performance.
struct definition of the unary node structures.
Definition: tree_node.hpp:1177
bool CheckIfPI(tree_nodeRef in, unsigned int BB_index)
Checks if the ssa variable is a primary input of lut network.
tree_nodeRef op0
The first operand of the binary expression.
Definition: tree_node.hpp:3021
#define VECT_CONTAINS(v, x)
#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
tree_nodeRef op1
The second operand of the binary expression.
Definition: tree_node.hpp:1217
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.
Class specification of the manager of the technology library data structures.
mockturtle::klut_network::signal(klut_network_ext::*)(const mockturtle::klut_network::signal, const mockturtle::klut_network::signal) klut_network_fn
Pointer that points to a function of klut_network_ext, that represents a binary operation between two...
Data structure describing a basic block at tree level.
signal create_ne(signal const a, signal const b)
Creates a &#39;not equal&#39; operation.
static std::vector< bool > IntegerToBitArray(integer_cst_t n, size_t size)
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.
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
std::vector< signal > create_or_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
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.
DesignFlowStep_Status InternalExec() override
Computes the operations CFG graph data structure.
std::vector< signal > create_xor_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
identify and optmize lut expressions.
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.
uint64_t po_index
in case the current node is a primary output, holds the index of the primary output ...
bool cannotBeLUT(tree_nodeRef op) const
cannotBeLUT returns true in case the op is an operation that cannot be translated in a LUT ...
static bool IsSignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of integer type.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
tree_nodeRef create_lut_expr(const tree_nodeConstRef &type, const tree_nodeRef &op0, const tree_nodeRef &op1, const tree_nodeRef &op2, const tree_nodeRef &op3, const tree_nodeRef &op4, const tree_nodeRef &op5, const tree_nodeRef &op6, const tree_nodeRef &op7, const tree_nodeRef &op8, const std::string &srcp) const
create_lut_expr: function used to create a generic lut_expr operation
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
static bool IsBooleanType(const tree_nodeConstRef &type)
Return true if the treenode is of bool type.
unsigned int bb_index
The basic block to which this gimple_node belongs.
Definition: tree_node.hpp:1134
APInt integer_cst_t
Definition: panda_types.hpp:47
This struct specifies the gimple_assign node (GCC 4.3 tree node).
Definition: tree_node.hpp:3015
std::vector< signal > create_not_v(std::vector< signal > const &a)
static const uint32_t k[]
Definition: sha-256.c:22
Class specification of the data structures used to manage technology information. ...
signal create_lut(std::vector< signal > s, long long f)
Creates a &#39;lut&#39; operation from an std::vector of mockturtle::klut_network::signal with the associated...
bool is_po
whether the current node is a primary output
const std::vector< enum kind > lutBooleanExpressibleOperations
The list of all operation that can be converted to a lut.
Classes to describe design flow graph.
tree_nodeRef CreateUniqueIntegerCst(integer_cst_t value, const tree_nodeConstRef &type)
memoization of integer constants
#define index(x, y)
Definition: Keccak.c:74
static const std::string ComputeSignature(const TechnologyFlowStep_Type technology_flow_step_type)
Compute the signature of a technology flow step.
kind
size_t max_lut_size
The maximum number of inputs of a lut.
Factory for technology flow step.
bool CHECK_BIN_EXPR_BOOL_SIZE(binary_expr *be) const
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
DesignFlowStep_Status GetStatus() const
Return the status of this design step.
const ParameterConstRef parameters
Set of input parameters.
std::vector< signal > create_and_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
DesignFlowStep_Status
The status of a step.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
std::vector< signal > create_gt_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
long long lut_constant
the lut constant
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
static std::string ConvertBitsToString(const std::vector< bool > &bits, const std::string &true_string="vdd", const std::string &false_string="gnd", const std::string &sep=", ")
Wrapper of design_flow.
tree_nodeRef GetBooleanType() const
Function that creates a boolean type if it is not already present, otherwise it returns the one that ...
std::vector< signal > create_le_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
static klut_network_fn GetBooleanNodeCreationFunction(enum kind code)
int result[SIZE]
Definition: adpcm.c:800
This struct specifies the block node.
Definition: tree_node.hpp:1820
This file collects some utility functions.
tree_nodeRef op0
The first operand of the binary expression.
Definition: tree_node.hpp:1214
Definition: APInt.hpp:53
constants used by HLS constants
signal create_gt(signal const a, signal const b)
Creates a &#39;greater&#39; operation.
refcount< T > lock() const
Definition: refcount.hpp:212
#define BUILTIN_SRCP
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
const unsigned int function_id
The index of the function to be analyzed.
static T ConvertHexToNumber(const std::string &hex0)
static void ParseKLutNetwork(const mockturtle::klut_network &klut, std::vector< klut_network_node > &luts)
bool CHECK_COND_EXPR_SIZE(cond_expr *ce) const
klut_network_ext class provides operations derived from the one already existing in mockturtle::klut_...
const application_managerRef AppM
The application manager.
Class specification of the tree_reindex support class.
static klut_network_fn_v GetIntegerNodeCreationFunction(enum kind code)
std::vector< signal > create_lt_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
#define NUM_CST_allocation_default_max_lut_size
The default number of inputs of a LUT.
tree_nodeRef GetUnsignedLongLongType() const
Function that creates a long long unsigned int type if it is not already present, otherwise return th...
std::vector< signal > create_ge_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
TVMArray b1[1]
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.
static bool IsStructType(const tree_nodeConstRef &type)
Return true if treenode is a record.
bool CHECK_NOT_EXPR_SIZE(unary_expr *ne) const
void fix_inputs_size(std::vector< signal > *a, std::vector< signal > *b, bool signedValues)
this class is used to manage the command-line or XML options.
std::vector< signal > create_ne_v(std::vector< signal > const &a, std::vector< signal > const &b, bool signedValues)
klut_network_node(uint64_t _index, long long _lut_constant, const std::vector< uint64_t > &_fan_in, bool _is_po, uint64_t _po_index, bool _is_constant)
tree_nodeRef create_extract_bit_expr(const tree_nodeRef &op0, const tree_nodeRef &op1, const std::string &srcp) const
refcount< tree_node > tree_nodeRef
RefCount type definition of the tree_node class structure.
Definition: tree_node.hpp:212
std::string container_to_string(_InputIt first, _InputIt last, const std::string &separator, bool trim_empty=true)
Definition: utility.hpp:122
std::vector< uint64_t > fan_in
a std::vector containing the indexes of all inputs of the current node
x
Return the smallest n such that 2^n >= _x.
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
int debug_level
The debug level.
uint64_t index
the index of the node
signal create_ge(signal const a, signal const b)
Creates a &#39;greater&#39; or equal operation.
std::vector< signal > create_buf_v(std::vector< signal > const &a)
~lut_transformation() override
Destructor.
bool ProcessBasicBlock(std::pair< unsigned int, blocRef > block)
struct definition of the binary node structures.
Definition: tree_node.hpp:1206
void create_po_v(std::vector< signal > pos)
tree_nodeRef op
op field is the operand of the unary expression
Definition: tree_node.hpp:1185
tree_nodeRef CreateBitSelectionNodeOrCast(const tree_nodeRef source, int index, std::vector< tree_nodeRef > &prev_stmts_to_add)
TVMArray c0[1]
signal create_eq(signal const a, signal const b)
Creates a &#39;equal&#39; operation.
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
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.
A brief description of the C++ Header File.
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
const FunctionBehaviorRef function_behavior
The function behavior of the function to be analyzed.
Helper structure that better represents a mockturtle::klut_network&#39;s node.
int sl
Definition: adpcm.c:105
#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