PandA-2024.02
discrepancy_analysis_c_writer.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  */
39 
40 #include "Discrepancy.hpp"
41 #include "Parameter.hpp"
44 #include "application_manager.hpp"
45 #include "behavioral_helper.hpp"
47 #include "call_graph.hpp"
48 #include "call_graph_manager.hpp"
49 #include "fu_binding.hpp"
50 #include "hls.hpp"
51 #include "hls_manager.hpp"
53 #include "language_writer.hpp"
54 #include "math_function.hpp"
55 #include "memory.hpp"
58 #include "string_manipulation.hpp"
59 #include "structural_objects.hpp"
60 #include "technology_node.hpp"
61 #include "time_info.hpp"
62 #include "tree_helper.hpp"
63 #include "tree_manager.hpp"
64 #include "tree_reindex.hpp"
65 
66 #include <filesystem>
67 
68 #define INT_TYPE 0
69 #define UINT_TYPE 1
70 #define FLOAT_TYPE 2
71 #define DOUBLE_TYPE 3
72 #define F_SIGN(out, in) (((out & 3) << 2) | (in & 3))
73 #define F_TYPE_IN(f_sign) (f_sign & 3)
74 #define F_TYPE_OUT(f_sign) ((f_sign >> 2) & 3)
75 
76 /*
77  * Newer versions of gcc support integer variables larger than 64 bits.
78  * These are not supported by bambu which treats them as vectors. But the
79  * tree_helper::is_vector function returns false for those large integers.
80  * This function is used to detect when an integer variable (non-vector)
81  * is actually handled as a vector from bambu
82  */
83 static inline bool is_large_integer(const tree_nodeConstRef& _tn)
84 {
85  const auto tn = _tn->get_kind() == tree_reindex_K ? GET_CONST_NODE(_tn) : _tn;
86  const auto type = GetPointer<const type_node>(tn);
87  THROW_ASSERT(type, "type_id " + STR(tn->index) + " is not a type");
88  if(tn->get_kind() != integer_type_K)
89  {
90  return false;
91  }
92  const auto it = GetPointer<const integer_type>(tn);
93  THROW_ASSERT(it, "type " + STR(tn->index) + " is not an integer type");
94  if((it->prec != type->algn && it->prec > 64) || (type->algn == 128))
95  {
96  return true;
97  }
98 
99  return false;
100 }
101 
103  const HLS_managerConstRef _HLSMgr,
104  const InstructionWriterRef _instruction_writer,
105  const IndentedOutputStreamRef _indented_output_stream,
106  const ParameterConstRef _parameters, bool _verbose)
107  : HLSCWriter(_c_backend_information, _HLSMgr, _instruction_writer, _indented_output_stream, _parameters, _verbose),
108  Discrepancy(_HLSMgr->RDiscr)
109 {
110  THROW_ASSERT((Param->isOption(OPT_discrepancy) && Param->getOption<bool>(OPT_discrepancy)) ||
111  (Param->isOption(OPT_discrepancy_hw) && Param->getOption<bool>(OPT_discrepancy_hw)),
112  "Step " + STR(__PRETTY_FUNCTION__) + " should not be added without discrepancy");
113  THROW_ASSERT(Discrepancy, "Discrepancy data structure is not correctly initialized");
114 }
115 
117 {
118  // exit function
120 void _Dec2Bin_(FILE* __bambu_testbench_fp, long long int num, unsigned int precision)
121 {
122 unsigned int i;
123 unsigned long long int ull_value = (unsigned long long int)num;
124 for(i = 0; i < precision; ++i)
125  fprintf(__bambu_testbench_fp, "%c", (((1LLU << (precision - i - 1)) & ull_value) ? '1' : '0'));
126 }
127 
128 void _Ptd2Bin_(FILE* __bambu_testbench_fp, unsigned char* num, unsigned int precision)
129 {
130 unsigned int i, j;
131 char value;
132 if(precision % 8)
133 {
134 value = *(num + precision / 8);
135 for(j = 8 - precision % 8; j < 8; ++j)
136  fprintf(__bambu_testbench_fp, "%c", (((1LLU << (8 - j - 1)) & value) ? '1' : '0'));
137 }
138 for(i = 0; i < 8 * (precision / 8); i = i + 8)
139 {
140 value = *(num + (precision / 8) - (i / 8) - 1);
141 for(j = 0; j < 8; ++j)
142  fprintf(__bambu_testbench_fp, "%c", (((1LLU << (8 - j - 1)) & value) ? '1' : '0'));
143 }
144 }
145 
146 float _Int32_ViewConvert(unsigned int i)
147 {
148 union
149 {
150 unsigned int bits;
151 float fp32;
152 } vc;
153 vc.bits = i;
154 return vc.fp32;
155 }
156 
157 double _Int64_ViewConvert(unsigned long long i)
158 {
159 union
160 {
161 unsigned long long bits;
162 double fp64;
163 } vc;
164 vc.bits = i;
165 return vc.fp64;
166 }
167 
168 unsigned char _FPs32Mismatch_(float c, float e, float max_ulp)
169 {
170 unsigned int binary_c = *((unsigned int*)&c);
171 unsigned int binary_e = *((unsigned int*)&e);
172 unsigned int binary_abs_c = binary_c & (~(1U << 31));
173 unsigned int binary_abs_e = binary_e & (~(1U << 31));
174 unsigned int denom_0 = 0x34000000;
175 unsigned int denom_e = ((binary_abs_e >> 23) - 23) << 23;
176 float cme = c - e;
177 unsigned int binary_cme = *((unsigned int*)&cme);
178 unsigned int binary_abs_cme = binary_cme & (~(1U << 31));
179 float abs_cme = *((float*)&binary_abs_cme);
180 float ulp = 0.0;
181 if(binary_abs_c > 0X7F800000 && binary_abs_c > 0X7F800000)
182  return 0;
183 else if(binary_abs_c == 0X7F800000 && binary_abs_e == 0X7F800000)
184 {
185 if((binary_c >> 31) != (binary_e >> 31))
186  return 1;
187 else
188  return 0;
189 }
190 else if(binary_abs_c == 0X7F800000 || binary_abs_e == 0X7F800000 || binary_abs_c > 0X7F800000 ||
191  binary_abs_e == 0X7F800000)
192  return 0;
193 else
194 {
195 if(binary_abs_e == 0)
196  ulp = abs_cme / (*((float*)&denom_0));
197 else
198  ulp = abs_cme / (*((float*)&denom_e));
199 return ulp > max_ulp;
200 }
201 }
202 
203 unsigned char _FPs64Mismatch_(double c, double e, double max_ulp)
204 {
205 unsigned long long int binary_c = *((unsigned long long int*)&c);
206 unsigned long long int binary_e = *((unsigned long long int*)&e);
207 unsigned long long int binary_abs_c = binary_c & (~(1ULL << 63));
208 unsigned long long int binary_abs_e = binary_e & (~(1ULL << 63));
209 unsigned long long int denom_0 = 0x3CB0000000000000;
210 unsigned long long int denom_e = ((binary_abs_e >> 52) - 52) << 52;
211 double cme = c - e;
212 unsigned long long int binary_cme = *((unsigned int*)&cme);
213 unsigned long long int binary_abs_cme = binary_cme & (~(1U << 31));
214 double abs_cme = *((double*)&binary_abs_cme);
215 double ulp = 0.0;
216 if(binary_abs_c > 0X7FF0000000000000 && binary_abs_c > 0X7FF0000000000000)
217  return 0;
218 else if(binary_abs_c == 0X7FF0000000000000 && binary_abs_e == 0X7FF0000000000000)
219 {
220 if((binary_c >> 63) != (binary_e >> 63))
221  return 1;
222 else
223  return 0;
224 }
225 else if(binary_abs_c == 0X7FF0000000000000 || binary_abs_e == 0X7FF0000000000000 ||
226  binary_abs_c > 0X7FF0000000000000 || binary_abs_e == 0X7FF0000000000000)
227  return 0;
228 else
229 {
230 if(binary_abs_e == 0)
231  ulp = abs_cme / (*((double*)&denom_0));
232 else
233  ulp = abs_cme / (*((double*)&denom_e));
234 return ulp > max_ulp;
235 }
236 }
237 
238 void _CheckBuiltinFPs32_(char* chk_str, unsigned char neq, float par_expected, float par_res, float par_a, float par_b)
239 {
240 if(neq)
241 {
242 printf("\n\n***********************************************************\nERROR ON A BASIC FLOATING POINT "
243  "OPERATION : %s : expected=%a (%.20e) res=%a (%.20e) a=%a (%.20e) b=%a "
244  "(%.20e)\n***********************************************************\n\n",
245  chk_str, par_expected, par_expected, par_res, par_res, par_a, par_a, par_b, par_b);
246 exit(1);
247 }
248 }
249 
250 void _CheckBuiltinFPs64_(char* chk_str, unsigned char neq, double par_expected, double par_res, double par_a,
251  double par_b)
252 {
253 if(neq)
254 {
255 printf("\n\n***********************************************************\nERROR ON A BASIC FLOATING POINT "
256  "OPERATION : %s : expected=%a (%.35e) res=%a (%.35e) a=%a (%.35e) b=%a "
257  "(%.35e)\n***********************************************************\n\n",
258  chk_str, par_expected, par_expected, par_res, par_res, par_a, par_a, par_b, par_b);
259 exit(1);
260 }
261 }
262 )");
263 }
264 
266 {
267  const auto top_symbols = Param->getOption<std::vector<std::string>>(OPT_top_functions_names);
268  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
269  const auto top_fnode = TM->GetFunction(top_symbols.front());
270  const auto top_fb = HLSMgr->CGetFunctionBehavior(GET_INDEX_CONST_NODE(top_fnode));
271  const auto top_bh = top_fb->CGetBehavioralHelper();
272  const auto top_fname = top_bh->get_function_name();
273  const auto return_type = tree_helper::GetFunctionReturnType(top_fnode);
274 
275  const auto& test_vectors = HLSMgr->RSim->test_vectors;
276 
277  indented_output_stream->Append("int main()\n{\n");
278  // write additional initialization code needed by subclasses
280  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Written extra init code");
281 
282  // parameters declaration
283  WriteParamDecl(top_bh);
284 
285  // ---- WRITE VARIABLES DECLARATIONS ----
286  // declaration of the return variable of the top function, if not void
287  if(return_type)
288  {
289  const auto ret_type = tree_helper::PrintType(TM, return_type);
290  if(tree_helper::IsVectorType(return_type))
291  {
292  THROW_ERROR("return type of function under test " + top_fname + " is " + STR(ret_type) +
293  "\nco-simulation does not support vectorized return types at top level");
294  }
295  indented_output_stream->Append("// return variable initialization\n");
296  indented_output_stream->Append(ret_type + " " RETURN_PORT_NAME ";\n");
297  }
298  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Written parameters declaration");
299  // ---- WRITE PARAMETERS INITIALIZATION AND FUNCTION CALLS ----
300  for(unsigned int v_idx = 0; v_idx < test_vectors.size(); v_idx++)
301  {
302  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Writing initialization for test vector " + STR(v_idx));
304  const auto& curr_test_vector = test_vectors.at(v_idx);
305  // write parameter initialization
306  indented_output_stream->Append("// parameter initialization\n");
307  WriteParamInitialization(top_bh, curr_test_vector);
309  // write the call to the top function to be tested
310  indented_output_stream->Append("// function call\n");
312 
314  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Written initialization for test vector " + STR(v_idx));
315  }
316  // print exit statements
317  indented_output_stream->Append("__standard_exit = 1;\n");
318  indented_output_stream->Append("exit(0);\n");
320 }
321 
323 {
324  const OpGraphConstRef instrGraph = FB->CGetOpGraph(FunctionBehavior::FCFG);
325  const OpNodeInfoConstRef node_info = instrGraph->CGetOpNodeInfo(statement);
326  const auto st_tn_id = node_info->GetNodeId();
327  if(st_tn_id == 0 || st_tn_id == ENTRY_ID || st_tn_id == EXIT_ID)
328  {
329  return;
330  }
331  const tree_nodeConstRef curr_tn = TM->CGetTreeNode(st_tn_id);
332  const auto kind = curr_tn->get_kind();
333  if(kind == gimple_return_K)
334  {
335  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CONTEXT_END\\n\");\n");
336  }
337  else if(kind == gimple_call_K)
338  {
339  THROW_ASSERT(!node_info->called.empty(),
340  "tree node " + STR(st_tn_id) + " is a gimple_call but does not actually call a function");
341  THROW_ASSERT(node_info->called.size() == 1, "tree node " + STR(st_tn_id) + " calls more than a function");
342  const auto called_id = *node_info->called.begin();
343  const tree_nodeConstRef called_fun_decl_node = TM->CGetTreeNode(called_id);
344  const auto* fu_dec = GetPointer<const function_decl>(called_fun_decl_node);
345  if(GetPointer<const identifier_node>(GET_NODE(fu_dec->name))->strg == BUILTIN_WAIT_CALL)
346  {
347  /*
348  * This operation calls a function with a function pointer, which is
349  * implemented in bambu with the builtin function * __builtin_wait_call()
350  * When a function is called with a function pointer we always need to
351  * have its C source code, so it always has to be printed back in C.
352  */
353  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CALL_ID " + STR(st_tn_id) + "\\n\");\n");
354  return;
355  }
356  const BehavioralHelperConstRef BH = HLSMgr->CGetFunctionBehavior(called_id)->CGetBehavioralHelper();
357  if(BH->has_implementation() && BH->function_has_to_be_printed(called_id))
358  {
359  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CALL_ID " + STR(st_tn_id) + "\\n\");\n");
360  }
361  }
362  else if(kind == gimple_assign_K)
363  {
364  const auto* g_as_node = GetPointer<const gimple_assign>(curr_tn);
365  tree_nodeRef rhs = GET_NODE(g_as_node->op1);
366  if(rhs->get_kind() == call_expr_K || rhs->get_kind() == aggr_init_expr_K)
367  {
368  THROW_ASSERT(!node_info->called.empty(), "rhs of gimple_assign node " + STR(st_tn_id) +
369  " is a call_expr but does not actually call a function");
370  THROW_ASSERT(node_info->called.size() == 1,
371  "rhs of gimple_assign node " + STR(st_tn_id) + " is a call_expr but calls more than a function");
372  const auto called_id = *node_info->called.begin();
373  const BehavioralHelperConstRef BH = HLSMgr->CGetFunctionBehavior(called_id)->CGetBehavioralHelper();
374  if(BH->has_implementation() && BH->function_has_to_be_printed(called_id))
375  {
376  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CALL_ID " + STR(st_tn_id) + "\\n\");\n");
377  }
378  }
379  }
380  return;
381 }
382 
384  const vertex statement)
385 {
386  if(Param->isOption(OPT_discrepancy_hw) && Param->getOption<bool>(OPT_discrepancy_hw))
387  {
388  /*
389  * if we're using hw discrepancy don't print anything after the
390  * instruction, because only control flow is checked
391  */
392  return;
393  }
394  const OpGraphConstRef instrGraph = fun_behavior->CGetOpGraph(FunctionBehavior::FCFG);
395  const auto st_tn_id = instrGraph->CGetOpNodeInfo(statement)->GetNodeId();
396  if(st_tn_id == 0 || st_tn_id == ENTRY_ID || st_tn_id == EXIT_ID)
397  {
398  return;
399  }
400  const tree_nodeConstRef curr_tn = TM->CGetTreeNode(st_tn_id);
401  if(curr_tn->get_kind() != gimple_assign_K && curr_tn->get_kind() != gimple_phi_K)
402  {
403  return;
404  }
405 
406  const BehavioralHelperConstRef BH = fun_behavior->CGetBehavioralHelper();
407  if(Param->isOption(OPT_discrepancy_only))
408  {
409  const auto discrepancy_functions = Param->getOption<CustomSet<std::string>>(OPT_discrepancy_only);
410  std::string fu_name = BH->get_function_name();
411  if(!discrepancy_functions.empty() && discrepancy_functions.find(fu_name) == discrepancy_functions.end())
412  {
413  return;
414  }
415  }
416  const auto funId = BH->get_function_index();
417  const hlsConstRef hls = HLSMgr->get_HLS(funId);
418 
419  technology_nodeRef fu_tech_n = hls->allocation_information->get_fu(hls->Rfu->get_assign(statement));
420  technology_nodeRef op_tech_n = GetPointer<functional_unit>(fu_tech_n)->get_operation(
421  tree_helper::NormalizeTypename(instrGraph->CGetOpNodeInfo(statement)->GetOperation()));
422 
423  const operation* oper = GetPointer<operation>(op_tech_n);
424  if(!oper)
425  {
426  return;
427  }
428 
429  const auto g_as_node = GetPointer<const gimple_assign>(curr_tn);
430  const auto g_phi_node = GetPointer<const gimple_phi>(curr_tn);
431  bool is_virtual = false;
432  tree_nodeRef ssa;
433  if(g_as_node)
434  {
435  ssa = g_as_node->op0;
436  }
437  else if(g_phi_node)
438  {
439  ssa = g_phi_node->res;
440  is_virtual = g_phi_node->virtual_flag;
441  }
442 
443  if(ssa && GET_CONST_NODE(ssa)->get_kind() == ssa_name_K && !is_virtual)
444  {
445  /*
446  * print statements that increase the counters used for coverage statistics
447  */
448  indented_output_stream->Append("__bambu_discrepancy_tot_assigned_ssa++;\n");
449  const auto* ssaname = GetPointerS<const ssa_name>(GET_CONST_NODE(ssa));
450  bool is_temporary = ssaname->var ? GetPointer<const decl_node>(GET_NODE(ssaname->var))->artificial_flag : true;
451  bool is_discrepancy_address = Discrepancy->address_ssa.count(ssa);
452  bool is_lost = Discrepancy->ssa_to_skip.count(ssa);
453  bool has_no_meaning_in_software = is_discrepancy_address && Discrepancy->ssa_to_skip_if_address.count(ssa);
454  if(is_lost || has_no_meaning_in_software)
455  {
456  indented_output_stream->Append("__bambu_discrepancy_tot_lost_ssa++;\n");
457  if(is_discrepancy_address)
458  {
459  indented_output_stream->Append("__bambu_discrepancy_tot_lost_addr_ssa++;\n");
460  if(is_temporary)
461  {
462  indented_output_stream->Append("__bambu_discrepancy_temp_lost_addr_ssa++;\n");
463  }
464  if(has_no_meaning_in_software)
465  {
466  /*
467  * These are ssa inserted by hls bit value optimization (like
468  * treating sums with bid shifts to use smaller hw components for
469  * sums). They are not present in the original source code and
470  * they have no meaning in sw, because they come from aggressive
471  * bit manipulations, which can originate intermediate address
472  * values that cannot be mapped in sw in any way.
473  */
474  indented_output_stream->Append("__bambu_discrepancy_opt_lost_addr_ssa++;\n");
476  }
477  }
478  else
479  {
480  THROW_ASSERT(!has_no_meaning_in_software,
481  "Tree Node " + STR(ssa->index) + " is has no meaning in software but is not an address");
482  indented_output_stream->Append("__bambu_discrepancy_tot_lost_int_ssa++;\n");
483  if(is_temporary)
484  {
485  indented_output_stream->Append("__bambu_discrepancy_temp_lost_int_ssa++;\n");
486  }
487  }
488  return;
489  }
490  else
491  {
492  indented_output_stream->Append("__bambu_discrepancy_tot_check_ssa++;\n");
493  if(is_discrepancy_address)
494  {
495  indented_output_stream->Append("__bambu_discrepancy_tot_check_addr_ssa++;\n");
496  if(is_temporary)
497  {
498  indented_output_stream->Append("__bambu_discrepancy_temp_check_addr_ssa++;\n");
499  }
500  }
501  else
502  {
503  indented_output_stream->Append("__bambu_discrepancy_tot_check_int_ssa++;\n");
504  if(is_temporary)
505  {
506  indented_output_stream->Append("__bambu_discrepancy_temp_check_int_ssa++;\n");
507  }
508  }
509  }
511  /*
512  * print statements to print information on the instruction
513  */
514  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"INSTR stg_id " + STR(funId) + " op_id " +
515  STR(instrGraph->CGetOpNodeInfo(statement)->GetNodeId()));
516 
517  if(oper->is_bounded())
518  {
521  }
522  else
523  {
525  }
526  indented_output_stream->Append("\\n\");\n");
527 
528  /*
529  * collect information on the scheduling of the operation to be printed
530  */
531  const auto STGMan = hls->STG;
532  const auto stg_info = STGMan->CGetStg()->CGetStateTransitionGraphInfo();
533 
534  CustomOrderedSet<unsigned int> init_state_ids;
535  CustomOrderedSet<unsigned int> exec_state_ids;
536  CustomOrderedSet<unsigned int> end_state_ids;
537 
538  for(const auto& s : STGMan->get_starting_states(statement))
539  {
540  init_state_ids.insert(stg_info->vertex_to_state_id.at(s));
541  }
542  for(const auto& s : STGMan->get_execution_states(statement))
543  {
544  exec_state_ids.insert(stg_info->vertex_to_state_id.at(s));
545  }
546  for(const auto& s : STGMan->get_ending_states(statement))
547  {
548  end_state_ids.insert(stg_info->vertex_to_state_id.at(s));
549  }
550 
551  THROW_ASSERT(!init_state_ids.empty(), "operation not properly scheduled: "
552  "number of init states = " +
553  STR(init_state_ids.size()));
554  THROW_ASSERT(!exec_state_ids.empty(), "operation not properly scheduled: "
555  "number of exec states = " +
556  STR(exec_state_ids.size()));
557  THROW_ASSERT(!end_state_ids.empty(), "operation not properly scheduled: "
558  "number of ending states = " +
559  STR(end_state_ids.size()));
560  /*
561  * print statements to print scheduling information on the operation
562  */
563  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"SCHED start");
564  for(const auto& s : init_state_ids)
565  {
566  indented_output_stream->Append(" " + STR(s));
567  }
568  indented_output_stream->Append("; exec");
569  for(const auto& s : exec_state_ids)
570  {
571  indented_output_stream->Append(" " + STR(s));
572  }
573  indented_output_stream->Append("; end");
574  for(const auto& s : end_state_ids)
575  {
576  indented_output_stream->Append(" " + STR(s));
577  }
578  indented_output_stream->Append(";\\n\");\n");
579 
580  const auto ssa_type = tree_helper::CGetType(ssa);
581  const auto type_bitsize = tree_helper::Size(ssa_type);
582  const auto var_name = BH->PrintVariable(ssa->index);
583  const auto ssa_bitsize = tree_helper::Size(ssa);
584  if(ssa_bitsize > type_bitsize)
585  {
586  THROW_ERROR(std::string("variable size mismatch: ") + "ssa node id = " + STR(ssa->index) + " has size = " +
587  STR(ssa_bitsize) + " type node id = " + STR(ssa_type->index) + " has size = " + STR(type_bitsize));
588  }
589  /* tree_nodeRef for gimple lvalue */
590  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, "
591  "\"ASSIGN ssa_id " +
592  STR(ssa->index) + "; ssa " + var_name + "; btsz " + STR(ssa_bitsize) +
593  "; val #\");\n");
594 
595  const bool is_real = tree_helper::IsRealType(ssa_type);
596  const bool is_vector = tree_helper::IsVectorType(ssa_type);
597  const bool is_complex = tree_helper::IsComplexType(ssa_type);
598 
599  if(is_real || is_complex || is_vector || tree_helper::IsStructType(ssa_type) ||
600  tree_helper::IsUnionType(ssa_type) || is_large_integer(ssa_type))
601  {
602  indented_output_stream->Append("_Ptd2Bin_(__bambu_discrepancy_fp, (unsigned char*)&" + var_name + ", " +
603  STR(type_bitsize) + ");\n");
604  }
605  else
606  {
607  indented_output_stream->Append("_Dec2Bin_(__bambu_discrepancy_fp, " + var_name + ", " + STR(type_bitsize) +
608  ");\n");
609  }
610 
611  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"; type ");
612 
613  THROW_ASSERT(!(is_discrepancy_address && (is_real || is_complex)),
614  "variable " + STR(var_name) + " with node id " + STR(ssa->index) + " has type id = " +
615  STR(ssa_type->index) + " is complex = " + STR(is_complex) + " is real = " + STR(is_real));
616 
617  auto vec_base_bitsize = type_bitsize;
618  if(is_vector)
619  {
620  THROW_ASSERT(ssa_bitsize == type_bitsize,
621  "ssa node id = " + STR(ssa->index) + " type node id = " + STR(ssa_type->index));
622 
623  const auto elem_bitsize = tree_helper::Size(tree_helper::CGetElements(ssa_type));
624 
625  THROW_ASSERT(type_bitsize % elem_bitsize == 0,
626  "ssa node id = " + STR(ssa->index) + " type node id = " + STR(ssa_type->index) +
627  " type_bitsize = " + STR(type_bitsize) + " elem_bitsize = " + STR(elem_bitsize));
628 
629  vec_base_bitsize = elem_bitsize;
631  }
632  else
633  {
635  }
636  indented_output_stream->Append(STR(vec_base_bitsize));
637 
638  if(is_complex)
639  {
640  THROW_ASSERT(vec_base_bitsize % 2 == 0, "complex variables must have size multiple of 2"
641  "\nssa node id = " +
642  STR(ssa->index) + "\ntype node id = " + STR(ssa_type->index) +
643  "\nvec_base_bitsize = " + STR(vec_base_bitsize));
645  }
646  else
647  {
649  }
650 
651  if(is_real)
652  {
654  }
655  else
656  {
658  }
659 
660  if(is_discrepancy_address)
661  {
663  }
664  else
665  {
667  }
668 
669  indented_output_stream->Append("\\n\");\n");
671  if(g_as_node)
672  {
673  const auto rhs = GET_CONST_NODE(g_as_node->op1);
674  if(rhs->get_kind() == call_expr_K || rhs->get_kind() == aggr_init_expr_K)
675  {
676  indented_output_stream->Append("//" + oper->get_name() + "\n");
677  const auto node_info = instrGraph->CGetOpNodeInfo(statement);
678  THROW_ASSERT(!node_info->called.empty(), "rhs of gimple_assign node " + STR(st_tn_id) +
679  " is a call_expr but does not actually call a function");
680  THROW_ASSERT(node_info->called.size() == 1, "rhs of gimple_assign node " + STR(st_tn_id) +
681  " is a call_expr but calls more than a function");
682  const auto called_id = *node_info->called.begin();
683  const auto BHC = HLSMgr->CGetFunctionBehavior(called_id)->CGetBehavioralHelper();
684  if(BHC->has_implementation() && BHC->function_has_to_be_printed(called_id))
685  {
686  const auto ce = GetPointerS<const call_expr>(rhs);
687  const auto& actual_args = ce->args;
688  const auto op0 = GET_CONST_NODE(ce->fn);
689  if(op0->get_kind() == addr_expr_K && (actual_args.size() == 1 || actual_args.size() == 2))
690  {
691  const auto ue = GetPointerS<const unary_expr>(op0);
692  const auto fn = GET_CONST_NODE(ue->op);
693  THROW_ASSERT(fn->get_kind() == function_decl_K,
694  "tree node not currently supported " + fn->get_kind_text());
695  const auto fd = GetPointerS<const function_decl>(fn);
696  if(fd)
697  {
698  static const std::map<std::string, std::pair<unsigned int, std::string>>
699  basic_unary_operations_relation = {
700  {"__int8_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, INT_TYPE), "(float)(int)"}},
701  {"__int16_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, INT_TYPE), "(float)(int)"}},
702  {"__int32_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, INT_TYPE), "(float)(int)"}},
703  {"__int32_to_float64e11m52b_1023nih", {F_SIGN(DOUBLE_TYPE, INT_TYPE), "(double)(int)"}},
704  {"__uint8_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, UINT_TYPE), "(float)"}},
705  {"__uint16_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, UINT_TYPE), "(float)"}},
706  {"__uint32_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, UINT_TYPE), "(float)"}},
707  {"__uint32_to_float64e11m52b_1023nih", {F_SIGN(DOUBLE_TYPE, UINT_TYPE), "(double)"}},
708  {"__int64_to_float32e8m23b_127nih",
709  {F_SIGN(FLOAT_TYPE, INT_TYPE), "(float)(long long int)"}},
710  {"__int64_to_float64e11m52b_1023nih",
711  {F_SIGN(DOUBLE_TYPE, INT_TYPE), "(double)(long long int)"}},
712  {"__uint64_to_float32e8m23b_127nih", {F_SIGN(FLOAT_TYPE, UINT_TYPE), "(float)"}},
713  {"__uint64_to_float64e11m52b_1023nih", {F_SIGN(DOUBLE_TYPE, UINT_TYPE), "(double)"}},
714  {"__float64_to_float32_ieee", {F_SIGN(FLOAT_TYPE, DOUBLE_TYPE), "(float)"}},
715  {"__float32_to_float64_ieee", {F_SIGN(DOUBLE_TYPE, FLOAT_TYPE), "(double)"}},
716  {"__float32_to_int32_round_to_zeroe8m23b_127nih", {F_SIGN(INT_TYPE, FLOAT_TYPE), "(int)"}},
717  {"__float32_to_int64_round_to_zeroe8m23b_127nih",
718  {F_SIGN(INT_TYPE, FLOAT_TYPE), "(long long int)"}},
719  {"__float32_to_uint32_round_to_zeroe8m23b_127nih",
720  {F_SIGN(UINT_TYPE, FLOAT_TYPE), "(unsigned int)"}},
721  {"__float32_to_uint64_round_to_zeroe8m23b_127nih",
722  {F_SIGN(UINT_TYPE, FLOAT_TYPE), "(unsigned long long int)"}},
723  {"__float64_to_int32_round_to_zeroe11m52b_1023nih",
724  {F_SIGN(INT_TYPE, DOUBLE_TYPE), "(int)"}},
725  {"__float64_to_int64_round_to_zeroe11m52b_1023nih",
726  {F_SIGN(INT_TYPE, DOUBLE_TYPE), "(long long int)"}},
727  {"__float64_to_uint32_round_to_zeroe11m52b_1023nih",
728  {F_SIGN(UINT_TYPE, DOUBLE_TYPE), "(unsigned int)"}},
729  {"__float64_to_uint64_round_to_zeroe11m52b_1023nih",
730  {F_SIGN(UINT_TYPE, DOUBLE_TYPE), "(unsigned long long int)"}},
731  };
732  static const std::map<std::string, std::pair<bool, std::string>> basic_binary_operations_relation =
733  {
734  {"__float_adde8m23b_127nih", {false, "+"}},
735  {"__float_sube8m23b_127nih", {false, "-"}},
736  {"__float_mule8m23b_127nih", {false, "*"}},
737  {"__float_divSRT4e8m23b_127nih", {false, "/"}},
738  {"__float_divGe8m23b_127nih", {false, "/"}},
739  {"__float_lee8m23b_127nih", {false, "<="}},
740  {"__float_lte8m23b_127nih", {false, "<"}},
741  {"__float_gee8m23b_127nih", {false, ">="}},
742  {"__float_gte8m23b_127nih", {false, ">"}},
743  {"__float_eqe8m23b_127nih", {false, "=="}},
744  {"__float_ltgt_quiete8m23b_127nih", {false, "!="}},
745  {"__float_adde11m52b_1023nih", {true, "+"}},
746  {"__float_sube11m52b_1023nih", {true, "-"}},
747  {"__float_mule11m52b_1023nih", {true, "*"}},
748  {"__float_divSRT4e11m52b_1023nih", {true, "/"}},
749  {"__float_divGe11m52b_1023nih", {true, "/"}},
750  {"__float_lee11m52b_1023nih", {true, "<="}},
751  {"__float_lte11m52b_1023nih", {true, "<"}},
752  {"__float_gee11m52b_1023nih", {true, ">="}},
753  {"__float_gte11m52b_1023nih", {true, ">"}},
754  {"__float_eqe11m52b_1023nih", {true, "=="}},
755  {"__float_ltgt_quiete11m52b_1023nih", {true, "!="}},
756  };
757  const auto unary_op_relation = basic_unary_operations_relation.find(oper->get_name());
758  const auto binary_op_relation = basic_binary_operations_relation.find(oper->get_name());
759  // Also check actual args count since they could have been optimized out
760  if(unary_op_relation != basic_unary_operations_relation.end() && actual_args.size() >= 1)
761  {
762  const auto& f_sign = unary_op_relation->second.first;
763  const auto& cast_op = unary_op_relation->second.second;
764  auto var1 = BHC->PrintVariable(GET_INDEX_NODE(actual_args.at(0)));
765  auto res_name = var_name;
766  if(F_TYPE_IN(f_sign) & FLOAT_TYPE)
767  {
768  const std::string view_convert =
769  F_TYPE_IN(f_sign) == FLOAT_TYPE ? "_Int32_ViewConvert" : "_Int64_ViewConvert";
770  var1 = view_convert + "(" + var1 + ")";
771  }
772  if(F_TYPE_OUT(f_sign) & FLOAT_TYPE)
773  {
774  const std::string view_convert =
775  F_TYPE_OUT(f_sign) == FLOAT_TYPE ? "_Int32_ViewConvert" : "_Int64_ViewConvert";
776  res_name = view_convert + "(" + res_name + ")";
777  }
778  const auto computation = "(" + cast_op + "(" + var1 + "))";
779  const auto check_string0 = "\"" + res_name + "==" + computation + "\"";
780  if(F_TYPE_OUT(f_sign) & FLOAT_TYPE)
781  {
782  const auto check_string1 =
783  (F_TYPE_OUT(f_sign) == FLOAT_TYPE ? "_FPs32Mismatch_(" : "_FPs64Mismatch_(") +
784  computation + ", " + res_name + "," + STR(Param->getOption<double>(OPT_max_ulp)) + ")";
786  (F_TYPE_OUT(f_sign) == FLOAT_TYPE ? "_CheckBuiltinFPs32_(" : "_CheckBuiltinFPs64_(") +
787  check_string0 + ", " + check_string1 + "," + computation + "," + var_name + "," + var1 +
788  ",0);\n");
789  }
790  else
791  {
792  const auto int_format = F_TYPE_OUT(f_sign) == INT_TYPE ? "%lld" : "%llu";
793  const auto int_cast =
794  F_TYPE_OUT(f_sign) == INT_TYPE ? "(long long int)" : "(long long unsigned int)";
795  const auto fp_format = F_TYPE_IN(f_sign) == FLOAT_TYPE ? "%.20e" : "%.35e";
797  "if(" + res_name + "!=" + computation +
798  ") { printf(\"\\n\\n***********************************************************\\nERROR "
799  "ON A BASIC FLOATING POINT OPERATION : %s : expected=" +
800  int_format + " res=" + int_format + "a=%a (" + fp_format +
801  ")\\n***********************************************************\\n\\n\", " +
802  check_string0 + ", " + int_cast + computation + ", " + int_cast + res_name + ", " +
803  var1 + ", " + var1 + ");\nexit(1);\n}\n");
804  }
805  }
806  else if(binary_op_relation != basic_binary_operations_relation.end() && actual_args.size() >= 2)
807  {
808  const auto& is_double_type = binary_op_relation->second.first;
809  const auto& op_symbol = binary_op_relation->second.second;
810  const std::string view_convert = is_double_type ? "_Int64_ViewConvert" : "_Int32_ViewConvert";
811  const auto var1 =
812  view_convert + "(" + BHC->PrintVariable(GET_INDEX_NODE(actual_args.at(0))) + ")";
813  const auto var2 =
814  view_convert + "(" + BHC->PrintVariable(GET_INDEX_NODE(actual_args.at(1))) + ")";
815  const auto res_name = view_convert + "(" + var_name + ")";
816  const auto computation = "(" + var1 + op_symbol + var2 + ")";
817  const auto check_string0 = "\"" + view_convert + "(" + var_name + ")==" + computation + "\"";
818  const auto check_string1 = (is_double_type ? "_FPs64Mismatch_" : "_FPs32Mismatch_") +
819  std::string("(") + computation + ", " + res_name + "," +
820  STR(Param->getOption<double>(OPT_max_ulp)) + ")";
822  (is_double_type ? "_CheckBuiltinFPs64_(" : "_CheckBuiltinFPs32_(") + check_string0 + ", " +
823  check_string1 + "," + computation + "," + res_name + "," + var1 + "," + var2 + ");\n");
824  }
825  }
826  }
827  }
828  }
829  }
830  }
831 }
832 
834 {
837  const bool is_hw_discrepancy = Param->isOption(OPT_discrepancy_hw) && Param->getOption<bool>(OPT_discrepancy_hw);
838 
839  indented_output_stream->Append("unsigned int __standard_exit;\n");
840  indented_output_stream->Append("FILE* __bambu_discrepancy_fp;\n");
841  indented_output_stream->Append("long long unsigned int __bambu_discrepancy_context = 0;\n");
842 
843  if(!is_hw_discrepancy)
844  {
846 long long unsigned int __bambu_discrepancy_tot_assigned_ssa = 0;
847 long long unsigned int __bambu_discrepancy_tot_lost_ssa = 0;
848 long long unsigned int __bambu_discrepancy_tot_check_ssa = 0;
849 long long unsigned int __bambu_discrepancy_tot_lost_addr_ssa = 0;
850 long long unsigned int __bambu_discrepancy_temp_lost_addr_ssa = 0;
851 long long unsigned int __bambu_discrepancy_opt_lost_addr_ssa = 0;
852 long long unsigned int __bambu_discrepancy_tot_lost_int_ssa = 0;
853 long long unsigned int __bambu_discrepancy_temp_lost_int_ssa = 0;
854 long long unsigned int __bambu_discrepancy_tot_check_addr_ssa = 0;
855 long long unsigned int __bambu_discrepancy_temp_check_addr_ssa = 0;
856 long long unsigned int __bambu_discrepancy_tot_check_int_ssa = 0;
857 long long unsigned int __bambu_discrepancy_temp_check_int_ssa = 0;
858 )");
859  }
860 
861  /*
862  * extra exit function to print out the statistics even in case
863  * __builtin_exit is called, which normally just terminates the program
864  */
865  indented_output_stream->Append("void __bambu_discrepancy_exit(void) __attribute__ ((destructor(101)));\n");
866  indented_output_stream->Append("void __bambu_discrepancy_exit(void)\n");
868  indented_output_stream->Append("if (__standard_exit) {\n");
869  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CONTEXT_END\\n\");\n");
871  indented_output_stream->Append("fflush(__bambu_discrepancy_fp);\n");
872  indented_output_stream->Append("fclose(__bambu_discrepancy_fp);\n");
873 
874  /*
875  * if we're using hw discrepancy don't print anything related to ssa
876  * variables or to results of operations, because only control flow is
877  * checked
878  */
879  if(!is_hw_discrepancy)
880  {
881  indented_output_stream->Append("fputs(\"DISCREPANCY REPORT\\n\", stdout);\n");
882  if(Param->isOption(OPT_cat_args))
883  {
884  indented_output_stream->Append("fputs(\"" + Param->getOption<std::string>(OPT_program_name) +
885  " executed with: " + Param->getOption<std::string>(OPT_cat_args) +
886  "\\n\", stdout);\n");
887  }
888  indented_output_stream->Append("fprintf(stdout, "
889  "\"Assigned ssa = %llu\\nChecked ssa = %llu\\nLost ssa = %llu\\n\", "
890  "__bambu_discrepancy_tot_assigned_ssa, __bambu_discrepancy_tot_check_ssa, "
891  "__bambu_discrepancy_tot_lost_ssa);\n");
893  "fprintf(stdout, "
894  "\"Normal ssa = %llu\\nAddress ssa = %llu\\n\", "
895  "__bambu_discrepancy_tot_lost_int_ssa + __bambu_discrepancy_tot_check_int_ssa, "
896  "__bambu_discrepancy_tot_lost_addr_ssa + __bambu_discrepancy_tot_check_addr_ssa);\n");
898  "fprintf(stdout, "
899  "\"CHECKED: %llu\\nNormal ssa = %llu\\nNormal tmp ssa = %llu\\nAddr ssa = %llu\\nAddr tmp ssa = %llu\\n\", "
900  "__bambu_discrepancy_tot_check_ssa, __bambu_discrepancy_tot_check_int_ssa, "
901  "__bambu_discrepancy_temp_check_int_ssa, "
902  "__bambu_discrepancy_tot_check_addr_ssa, __bambu_discrepancy_temp_check_addr_ssa);\n");
903  indented_output_stream->Append("fprintf(stdout, "
904  "\"LOST: %llu\\nNormal ssa lost = %llu\\nNormal tmp ssa lost = %llu\\nAddr ssa "
905  "lost = %llu\\nAddr tmp ssa lost = %llu\\nOpt tmp ssa lost = %llu\\n\", "
906  "__bambu_discrepancy_tot_lost_ssa, __bambu_discrepancy_tot_lost_int_ssa, "
907  "__bambu_discrepancy_temp_lost_int_ssa, "
908  "__bambu_discrepancy_tot_lost_addr_ssa, __bambu_discrepancy_temp_lost_addr_ssa, "
909  "__bambu_discrepancy_opt_lost_addr_ssa);\n");
910  }
911  indented_output_stream->Append("}\n\n");
912  return;
913 }
914 
916 {
917  const auto top_symbols = Param->getOption<std::vector<std::string>>(OPT_top_functions_names);
918  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
919  const auto top_fnode = TM->GetFunction(top_symbols.front());
920  const auto fun_behavior = HLSMgr->CGetFunctionBehavior(GET_INDEX_CONST_NODE(top_fnode));
921  const auto behavioral_helper = fun_behavior->CGetBehavioralHelper();
922  Discrepancy->c_trace_filename = std::filesystem::path(c_backend_info->out_filename).parent_path().string() +
923  behavioral_helper->get_function_name() + "_discrepancy.data";
924 
925  indented_output_stream->Append("__standard_exit = 0;\n");
926  indented_output_stream->Append("__bambu_discrepancy_fp = fopen(\"" + Discrepancy->c_trace_filename +
927  "\", \"w\");\n");
928  indented_output_stream->Append("if (!__bambu_discrepancy_fp) {\n");
929  indented_output_stream->Append("perror(\"can't open file: " + Discrepancy->c_trace_filename + "\");\n");
930  indented_output_stream->Append("exit(1);\n");
931  indented_output_stream->Append("}\n\n");
932 
934  "fprintf(__bambu_discrepancy_fp, \"CONTEXT LL_%llu\\n\", __bambu_discrepancy_context);\n");
935  if(Param->isOption(OPT_discrepancy_hw) && Param->getOption<bool>(OPT_discrepancy_hw))
936  {
937  /*
938  * if we're using hw discrepancy don't print anything related to global
939  * variables, because only control flow is checked
940  */
941  return;
942  }
943  for(const auto& var_node : HLSMgr->GetGlobalVariables())
944  {
945  if(HLSMgr->Rmem->has_base_address(var_node->index) && !tree_helper::IsSystemType(var_node))
946  {
947  const auto bitsize = tree_helper::Size(var_node);
948  THROW_ASSERT(bitsize % 8 == 0 || bitsize == 1,
949  "bitsize of a variable in memory must be multiple of 8 --> is " + STR(bitsize));
950  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"VARDECL_ID " + STR(var_node->index) +
951  " VAR_ADDR LL_%lu\\n\", &" +
952  STR(behavioral_helper->PrintVariable(var_node->index)) + ");//size " +
953  STR(compute_n_bytes(bitsize)) + "\n");
954  }
955  }
956 }
957 
959 {
960  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CALL_ID 0\\n\");\n");
961 }
962 
964  CustomSet<unsigned int>& already_declared_variables,
965  CustomSet<std::string>& locally_declared_types,
966  const BehavioralHelperConstRef BH,
967  const var_pp_functorConstRef varFunc)
968 {
969  HLSCWriter::DeclareLocalVariables(to_be_declared, already_declared_variables, locally_declared_types, BH, varFunc);
970  indented_output_stream->Append("__bambu_discrepancy_context++;\n");
972  "fprintf(__bambu_discrepancy_fp, \"CONTEXT LL_%llu\\n\", __bambu_discrepancy_context);\n");
973  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"CALLED_ID " + STR(BH->get_function_index()) +
974  "\\n\");\n");
975  if(Param->isOption(OPT_discrepancy_hw) && Param->getOption<bool>(OPT_discrepancy_hw))
976  {
977  /*
978  * if we're using hw discrepancy don't print anything related memory,
979  * because only control flow is checked
980  */
981  return;
982  }
983  const auto FB = HLSMgr->CGetFunctionBehavior(BH->get_function_index());
984  for(const auto& par : BH->GetParameters())
985  {
986  if(FB->is_variable_mem(GET_INDEX_CONST_NODE(par)))
987  {
988  const auto bitsize = tree_helper::Size(par);
989  THROW_ASSERT(bitsize % 8 == 0 || bitsize == 1,
990  "bitsize of a variable in memory must be multiple of 8 --> is " + STR(bitsize));
991  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"VARDECL_ID " +
992  STR(GET_INDEX_CONST_NODE(par)) + " VAR_ADDR LL_%lu\\n\", &" +
993  STR(BH->PrintVariable(GET_INDEX_CONST_NODE(par))) + ");//size " +
994  STR(compute_n_bytes(bitsize)) + "\n");
995  }
996  }
997  for(const auto& var : to_be_declared)
998  {
999  if(FB->is_variable_mem(var))
1000  {
1001  const auto bitsize = tree_helper::Size(TM->CGetTreeReindex(var));
1002  THROW_ASSERT(bitsize % 8 == 0 || bitsize == 1,
1003  "bitsize of a variable in memory must be multiple of 8 --> is " + STR(bitsize));
1004  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"VARDECL_ID " + STR(var) +
1005  " VAR_ADDR LL_%lu\\n\", &" + STR(BH->PrintVariable(var)) + ");//size " +
1006  STR(compute_n_bytes(bitsize)) + "\n");
1007  }
1008  }
1009 }
1010 
1012 {
1013  const auto FB = HLSMgr->CGetFunctionBehavior(function_index);
1014  const auto BH = FB->CGetBehavioralHelper();
1015  const auto funName = BH->get_function_name();
1016  const auto node_fun = TM->GetTreeNode(function_index);
1017  THROW_ASSERT(GetPointer<function_decl>(node_fun), "expected a function decl");
1018  bool prepend_static = !tree_helper::is_static(TM, function_index) && !tree_helper::is_extern(TM, function_index) &&
1019  (funName != "main");
1020  if(prepend_static)
1021  {
1022  GetPointerS<function_decl>(node_fun)->static_flag = true;
1023  }
1024  CWriter::WriteFunctionImplementation(function_index);
1025  if(prepend_static)
1026  {
1027  GetPointerS<function_decl>(node_fun)->static_flag = false;
1028  }
1029 }
1030 
1031 void DiscrepancyAnalysisCWriter::WriteBBHeader(const unsigned int bb_number, const unsigned int function_index)
1032 {
1033  indented_output_stream->Append("fprintf(__bambu_discrepancy_fp, \"stg_id " + STR(function_index) + " BB " +
1034  STR(bb_number) + "\\n\");\n");
1035 }
1036 
1038 {
1039  const auto FB = HLSMgr->CGetFunctionBehavior(funId);
1040  const auto BH = FB->CGetBehavioralHelper();
1041  const auto funName = BH->get_function_name();
1042  const auto node_fun = TM->GetTreeNode(funId);
1043  THROW_ASSERT(GetPointer<function_decl>(node_fun), "expected a function decl");
1044  const auto prepend_static =
1045  !tree_helper::is_static(TM, funId) && !tree_helper::is_extern(TM, funId) && (funName != "main");
1046  if(prepend_static)
1047  {
1048  GetPointerS<function_decl>(node_fun)->static_flag = true;
1049  }
1051  if(prepend_static)
1052  {
1053  GetPointerS<function_decl>(node_fun)->static_flag = false;
1054  }
1055 }
1056 
1058 {
1060 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
void WriteGlobalDeclarations() override
Writes the global declarations.
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
static bool IsUnionType(const tree_nodeConstRef &type)
Return if treenode is an union.
static bool IsComplexType(const tree_nodeConstRef &type)
Return if treenode is a complex.
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;.
void WriteFunctionDeclaration(const unsigned int funId) override
Writes the declaration of the function whose id in the tree is funId.
const CBackendInformationConstRef c_backend_info
Backend information.
This file contains the structures needed to manage a graph that will represent the state transition g...
const tree_nodeRef CGetTreeReindex(const unsigned int i) const
Return a tree_reindex wrapping the i-th tree_node.
std::string get_function_name() const
Return the name of the function.
int debug_level
the debug level
Definition: c_writer.hpp:122
Definition of the class representing a generic C application.
void WriteBBHeader(const unsigned int bb_number, const unsigned int function_index) override
mathematical utility function not provided by standard libraries
bool is_bounded() const
std::vector< tree_nodeRef > GetParameters() const
Return the list of index of original parameters of the function.
void WriteFunctionImplementation(unsigned int function_index) override
Write function implementation.
static bool is_static(const tree_managerConstRef &TM, const unsigned int index)
FIXME: to be remove after substitution with IsStaticDeclaration.
static tree_nodeConstRef CGetElements(const tree_nodeConstRef &type)
Given an array or a vector return the element type.
std::string c_trace_filename
name of the file that contains the c trace to parse
unsigned int get_function_index() const
Return the index of the function.
Collect information about resource performance.
Class to print indented code.
time_infoRef time_m
class representing the timing information associated with this operation
#define BUILTIN_WAIT_CALL
constant defining the builtin wait call intrinsic function
Definition: op_graph.hpp:358
#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
unsigned long long n_checked_operations
TreeNodeSet ssa_to_skip_if_address
Set of tree nodes.
const tree_managerConstRef TM
The tree manager.
Definition: c_writer.hpp:98
void DeclareLocalVariables(const CustomSet< unsigned int > &to_be_declared, CustomSet< unsigned int > &already_declared_variables, CustomSet< std::string > &locally_declared_type, const BehavioralHelperConstRef BH, const var_pp_functorConstRef varFunc) override
Declares the local variable; in case the variable used in the initialization of curVar hasn&#39;t been de...
#define RETURN_PORT_NAME
void WriteExtraInitCode() override
Write additional initialization code needed by subclasses.
Base class to pass information to a c backend.
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
bool has_implementation() const
Return true if function has implementation.
virtual void WriteFunctionDeclaration(const unsigned int funId)
Writes the declaration of the function whose id in the tree is funId.
Definition: c_writer.cpp:372
unsigned int get_cycles() const
Definition: time_info.cpp:95
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.
void WriteTestbenchFunctionCall(const BehavioralHelperConstRef behavioral_helper)
Writes a call to the top function to be tested, using its parameters.
#define F_SIGN(out, in)
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
static bool is_large_integer(const tree_nodeConstRef &_tn)
const IndentedOutputStreamRef indented_output_stream
Represents the stream we are currently writing to.
Definition: c_writer.hpp:101
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
#define EXIT_ID
constant used to represent tree node index of exit operation
Definition: op_graph.hpp:81
static bool IsSystemType(const tree_nodeConstRef &type)
Return true if variable or type is a system one.
This class specifies the characteristic of a particular operation working on a given functional unit...
void WriteParamInitialization(const BehavioralHelperConstRef behavioral_helper, const std::map< std::string, std::string > &curr_test_vector)
Initialize the parameters of the function.
const ParameterConstRef Param
set of parameters
Definition: c_writer.hpp:119
void Append(const std::string &str)
Append a string to the output.
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
Class specification of the data structures used to manage technology information. ...
TreeNodeSet address_ssa
Set of tree nodes representing the ssa_name to be treated as addresses in discrepancy analysis...
#define F_TYPE_IN(f_sign)
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
kind
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
This file contains the structures needed to manage a graph that will represent the state transition g...
void WriteMainTestbench() override
Writes the main() of the testbench C program.
const std::string & get_name() const override
Returns the name of the operation.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
const BehavioralHelperConstRef CGetBehavioralHelper() const
Returns the helper associated with the function.
static std::string NormalizeTypename(const std::string &id)
Return normalized name of types and variables.
This package is used by all HLS packages to manage resource constraints and characteristics.
bool function_has_to_be_printed(unsigned int f_id) const
returns true if the function body has to be printed by the C backend
Call graph hierarchy.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
std::string PrintVariable(unsigned int var) const
Print the name of the variable associated to the index.
T compute_n_bytes(T bitsize)
This file collects some utility functions.
tree_nodeRef GetTreeNode(const unsigned int index) const
Return the index-th tree_node (modifiable version)
DiscrepancyAnalysisCWriter(const CBackendInformationConstRef _c_backend_information, const HLS_managerConstRef _HLSMgr, const InstructionWriterRef _instruction_writer, const IndentedOutputStreamRef _indented_output_stream, const ParameterConstRef _parameters, bool _verbose)
Constructor.
void WriteBuiltinWaitCall() override
Writes implementation of __builtin_wait_call.
const HLS_managerConstRef HLSMgr
the hls manager
Definition: c_writer.hpp:95
TreeNodeSet ssa_to_skip
Set of tree nodes representing the ssa_name to be skipped in discrepancy analysis.
void writePreInstructionInfo(const FunctionBehaviorConstRef FB, const vertex statement) override
Write extra information on the given statement vertex, before the statement itself.
This class describes all classes used to represent a structural object.
Class specification of the tree_reindex support class.
#define ENTRY_ID
constant used to represent tree node index of entry operation
Definition: op_graph.hpp:79
Data structure used to store the functional-unit binding of the vertexes.
const OpGraphConstRef CGetOpGraph(FunctionBehavior::graph_type gt) const
This method returns the operation graphs.
virtual void DeclareLocalVariables(const CustomSet< unsigned int > &to_be_declared, CustomSet< unsigned int > &already_declared_variables, CustomSet< std::string > &already_declared_types, const BehavioralHelperConstRef behavioral_helper, const var_pp_functorConstRef varFunc)
Declares the local variable; in case the variable used in the intialization of curVar hasn&#39;t been dec...
Definition: c_writer.cpp:1393
static std::string PrintType(const tree_managerConstRef &TM, const tree_nodeConstRef &type, bool global=false, bool print_qualifiers=false, bool print_storage=false, const tree_nodeConstRef &var=nullptr, const var_pp_functorConstRef &vppf=var_pp_functorConstRef(), const std::string &prefix="", const std::string &tail="")
Print a type and its variable in case var is not zero.
void writePostInstructionInfo(const FunctionBehaviorConstRef fun_behavior, const vertex) override
Write extra information on the given statement vertex, after the statement itself.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
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.
static bool is_extern(const tree_managerConstRef &TM, const unsigned int index)
FIXME: to be remove after substitution with IsExternDeclaration.
virtual void WriteBuiltinWaitCall()
Writes implementation of __builtin_wait_call.
Definition: c_writer.cpp:1922
#define F_TYPE_OUT(f_sign)
this class is used to manage the command-line or XML options.
virtual void WriteGlobalDeclarations()
Writes the global declarations.
Definition: c_writer.cpp:307
Wrapper to call graph.
Control flow graph with feedback.
Data structure that contains all information about high level synthesis process.
Definition: hls.hpp:83
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
Data structure definition for high-level synthesis flow.
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
tree_nodeRef GetFunction(const std::string &function_name) const
Return the index of a function given its name.
void WriteParamDecl(const BehavioralHelperConstRef behavioral_helper)
Write declaration of the top function parameters.
Datastructure to represent memory information in high-level synthesis.
Class specification of the manager of the tree structures extracted from the raw file.
virtual void WriteFunctionImplementation(unsigned int function_id)
Write function implementation.
Definition: c_writer.cpp:258
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
#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:51 for PandA-2024.02 by doxygen 1.8.13